Datadog이 지금도 여러 프로세스로 나뉘어 동작하는 이유


Datadog은 20개가 넘는 바이너리로 구성될 만큼 거대한 서비스입니다. 개발자와 운영자에게 다양한 관측 데이터를 제공하는 플랫폼인 만큼, 초창기부터 구현해야 할 기능도 많았습니다.

Datadog은 원래 파이썬으로 만들어졌는데, 파이썬에는 GIL(Global Interpreter Lock, 전역 인터프리터 락)이라는 제약이 있어 하나의 프로세스에서 동시에 실행할 수 있는 스레드가 단 하나뿐입니다. (이는 파이썬의 메모리 관리 방식과 맞닿아 있는 이야기라 다음 글에서 따로 다뤄보겠습니다.)

여기서 좀 흥미로웠던 점은, ‘전역’이라는 이름 그대로 이 락이 멀티코어 환경에도 그대로 적용된다는 것이었습니다. 즉 파이썬은 애초에 멀티코어를 제대로 활용할 수 없는 구조였고, 그래서 초창기 Datadog 프로그램도 멀티코어를 쓰기 위해 여러 프로세스로 나눠 동작할 수밖에 없었습니다.

지금은 코드 대부분이 Go로 옮겨갔으니 ‘이제는 프로세스 하나로 다 띄우지 않을까’ 싶었는데, 실제로는 여전히 여러 프로세스로 나뉘어 동작하고 있었습니다. 왜 그런지 궁금해서 찾아본 이유는 이렇습니다.

가장 먼저 떠오른 이유는 권한 분리였습니다. 예를 들어 eBPF를 사용하는 기능은 root 권한이 필요하기 때문에, 다른 일반 기능들과는 다른 특권이 요구됩니다.

그런데 찾아보니 프로세스 하나로도 권한을 나눠서 처리하는 방법이 있긴 합니다. 높은 권한으로 시작해 필요한 특권 작업을 먼저 수행한 뒤, 이후에는 권한을 낮춰서 나머지 작업을 이어가는 방식(privilege dropping)입니다.

다만 이 경우에도 결국 같은 프로세스, 같은 주소 공간을 공유하게 됩니다. MMU 같은 메모리 보호 장치로 애초에 공간 자체가 분리되는 것이 아니기 때문에, 권한을 낮췄다고 해도 여전히 위험이 남습니다.

여기에 더해, 기능별로 장애를 격리하고 각자 독립적인 라이프사이클을 가져갈 수 있다는 점도 프로세스를 분리하는 중요한 이유였습니다.

결국 프로세스를 여러 개로 나누는 큰 그림 자체는 파이썬 시절과 똑같습니다. 다만 달라진 점이 있다면, Go로 넘어오면서 스레드로 멀티코어를 활용할 수 있게 됐기 때문에 예전처럼 코어를 쓰기 위해 무작정 프로세스를 쪼갤 필요는 없어졌다는 것입니다. 대신 기능 단위로 필요한 프로세스만 묶어서 구성할 수 있게 됐습니다. 즉 프로세스가 여러 개라는 결과는 같아도, 그 개수와 경계를 정하는 기준이 “코어 개수”에서 “기능 단위(권한·장애 격리·라이프사이클)“로 바뀐 셈입니다.


당연한 결론일 수도 있지만, AI에게 Datadog의 언어 변화 과정을 물어봤을 때 파이썬에서 Go로 넘어갔다는 답과 함께 “이제는 프로세스를 여러 개 띄우지 않아도 된다”는 뉘앙스의 내용이 나와서, 궁금한 마음에 직접 찾아보고 정리해봤습니다.