Datadog / database-design

59 개의 포스트

datadog

When upserts don't update but still write: Debugging Postgres performance at scale (새 탭에서 열림)

데이터독(Datadog)은 수백만 개의 일시적인 호스트 메타데이터를 효율적으로 관리하기 위해 새로운 업서트(Upsert) 쿼리를 도입했으나, 예상과 달리 디스크 쓰기와 WAL(Write-Ahead Logging) 동기화가 급증하는 문제에 직면했습니다. 조사 결과, PostgreSQL의 `ON CONFLICT DO UPDATE` 구문은 `WHERE` 조건에 의해 실제 업데이트가 수행되지 않더라도 행 잠금을 위해 WAL 레코드를 생성한다는 점이 원인이었습니다. 이 글은 고성능 시스템에서 단순한 쿼리 최적화 가정이 어떻게 물리적 성능 병목으로 이어질 수 있는지, 그리고 이를 어떻게 진단했는지 설명합니다. ### 효율적인 업서트 테이블 설계 * **업데이트 비용 절감:** PostgreSQL은 MVCC(MultiVersion Concurrency Control)를 사용하므로 업데이트 시마다 새로운 행 버전이 생성됩니다. 메타데이터 테이블의 비대화를 막기 위해 `last_ingested` 필드를 별도의 전용 테이블로 분리하여 쓰기 데이터양을 최소화했습니다. * **HOT(Heap-Only Tuples) 업데이트 활용:** 인덱스가 있는 컬럼을 수정하면 인덱스 페이지도 함께 수정되어야 합니다. 이를 피하기 위해 `last_ingested` 컬럼에는 인덱스를 생성하지 않았으며, `fillfactor`를 80%로 설정하여 페이지 내 여유 공간을 확보함으로써 HOT 업데이트가 가능하도록 설계했습니다. * **업데이트 빈도 제한:** 7일간 데이터가 없는 호스트를 식별하는 것이 목적이므로 1일 단위의 정밀도로 충분했습니다. 따라서 `WHERE` 절을 사용하여 마지막 업데이트로부터 24시간이 지난 경우에만 실제 쓰기가 발생하도록 쿼리를 구성했습니다. ### 예상치 못한 성능 지표의 변화 * **I/O 및 WAL 동기화 급증:** 쿼리 배포 후 업데이트 속도는 예상대로 낮게 유지되었으나, 디스크 쓰기 IOPS는 2배, WAL sync 횟수는 4배나 증가했습니다. * **쓰기 예산 소모:** PostgreSQL 클러스터는 단일 라이터(writer) 구조이므로 처리 가능한 쓰기 작업량에 한계가 있습니다. 실제 데이터 변경이 없는 'No-op' 쿼리들이 이 한정된 자원을 과도하게 소모하는 문제가 발생했습니다. * **내부 동작의 모순:** `INSERT ... ON CONFLICT DO UPDATE` 문에서 `WHERE` 조건이 거짓(false)이 되어 행이 업데이트되지 않더라도, 데이터베이스는 동시성 제어를 위해 해당 행에 락(lock)을 겁니다. 이 잠금 행위 자체가 WAL에 기록되면서 물리적인 쓰기 부하를 유발한 것입니다. ### pg_walinspect를 이용한 심층 진단 * **WAL 레코드 조사:** Postgres 15에서 도입된 `pg_walinspect` 확장 프로그램을 사용하여 실제 WAL에 어떤 데이터가 기록되고 있는지 분석했습니다. * **진단 도구 설정:** `pg_get_wal_records_info` 함수를 호출하여 특정 LSN(Log Sequence Number) 범위 내의 레코드를 확인했습니다. 이를 통해 쿼리 실행 시 업데이트가 발생하지 않음에도 불구하고 WAL 레코드가 생성되는 과정을 구체적으로 확인했습니다. * **원인 규명:** 분석 결과, `ON CONFLICT` 상황에서 잠금 처리가 WAL에 기록되는 것을 확인했으며, 이것이 전체적인 디스크 I/O 상승의 주범임을 입증했습니다. ### 실용적인 제언 PostgreSQL에서 고빈도 업서트를 설계할 때는 `WHERE` 조건문이 애플리케이션 레벨의 논리적 업데이트는 막아줄 수 있지만, 데이터베이스 엔진 레벨의 물리적 쓰기(WAL)까지 완전히 차단하지 못할 수 있음을 유의해야 합니다. 극도로 높은 처리량이 요구되는 환경에서는 `pg_walinspect`와 같은 도구를 사용하여 쿼리의 물리적 오버헤드를 사전에 검증하고, 불필요한 잠금 발생을 줄이는 방향으로 쿼리를 재작성하는 과정이 필수적입니다.

datadog

When an AI agent came knocking: Catching malicious contributions in Datadog’s open source repos (새 탭에서 열림)

데이터독(Datadog)은 최근 GitHub Actions 및 LLM 기반 워크플로우를 표적으로 삼는 AI 에이전트 'hackerbot-claw'의 악성 기여 시도를 성공적으로 차단했습니다. 이 공격은 AI 기술을 활용해 오픈소스 리포지토리에 취약점을 주입하려는 시도였으나, 데이터독의 AI 기반 탐지 시스템인 'BewAIre'와 선제적인 CI/CD 보안 제어 덕분에 무력화되었습니다. 이번 사례는 공격자들이 LLM을 통해 공격 규모를 확장함에 따라, 방어자 또한 AI를 보안 체계에 적극적으로 도입해야 함을 시사합니다. **오픈소스 CI 파이프라인을 향한 주요 공격 벡터** - **변수 삽입 취약점:** PR 제목과 같이 사용자가 제어할 수 있는 변수를 워크플로우 스크립트 내에 안전하지 않게 삽입하는 경우를 악용합니다. - **I-PPE(간접 포이즌 파이프라인 실행):** 악성 의존성이나 빌드 지침을 PR에 삽입하여 빌드 과정에서 자동으로 실행되게 함으로써 CI 비밀번호(Secrets)를 탈취합니다. - **`pull_request_target` 오용:** 신뢰할 수 없는 PR에서 실행되는 워크플로우에 높은 권한을 부여하는 설정을 악용하여 시스템을 장악합니다. - **LLM 프롬프트 인젝션:** `claude-code-action`이나 `run-gemini-cli`처럼 LLM을 사용하는 GitHub 액션에 악의적인 지시를 주입하여 자동화된 트리징 시스템을 교란합니다. **AI 기반 탐지 시스템 'BewAIre'의 운영** - **실시간 코드 리뷰:** 매주 유입되는 약 10,000건의 내외부 PR을 대상으로 LLM 기반의 자동화된 보안 검사를 수행합니다. - **2단계 분석 파이프라인:** GitHub 이벤트를 통해 코드 차분(diff) 데이터를 추출 및 정규화한 뒤, 2단계 LLM 파이프라인을 거쳐 변경 사항을 '악성' 또는 '정상'으로 분류하고 그 근거를 구조화하여 제시합니다. - **SIEM 통합 및 대응:** 악성으로 판정된 결과는 즉시 Datadog Cloud SIEM으로 전송되어 보안 사고 대응 팀(SIRT)이 즉각적으로 조사하고 사고화할 수 있도록 지원합니다. **선제적인 인프라 강화 및 보안 모범 사례** - **최소 권한의 임시 자격 증명:** OIDC identity federation을 활용한 `dd-octo-sts-action`을 도입하여, 수명이 길고 권한이 과도한 개인 액세스 토큰(PAT) 대신 수명이 짧고 권한이 제한된 인증 정보를 동적으로 생성합니다. - **비밀 정보 관리:** 수천 개의 리포지토리를 전수 조사하여 사용되지 않는 GitHub Actions 비밀 정보를 대규모로 식별하고 제거했습니다. - **CI 보안 정책 강제화:** 브랜치 보호 규칙, 휴먼 및 봇의 커밋 서명 의무화, 필수 PR 승인 절차를 도입하고 `GITHUB_TOKEN` 권한을 기본적으로 최소 수준으로 설정했습니다. - **보안 골든 패스(Golden Paths):** 엔지니어들이 별도의 복잡한 설정 없이도 보안이 확보된 표준 CI 파이프라인을 사용할 수 있도록 가이드를 문서화하고 시스템화했습니다. AI 에이전트를 활용한 공격이 현실화됨에 따라 단순한 규칙 기반의 탐지는 한계에 직면해 있습니다. 조직은 BewAIre와 같은 AI 기반 탐지 모델을 구축함과 동시에, OIDC를 통한 인증 체계 개선 및 GITHUB_TOKEN 권한 최소화와 같은 근본적인 CI/CD 보안 설정을 병행하여 자동화된 공격에 대한 방어 계층을 다각화해야 합니다.

datadog

Designing MCP tools for agents: Lessons from building Datadog's MCP server (새 탭에서 열림)

AI 에이전트를 위한 관측성(Observability) 인터페이스 구축 시, 단순히 기존 API를 그대로 노출하는 방식은 컨텍스트 창의 한계와 비용 문제로 인해 한계가 명확합니다. Datadog은 MCP(Model Context Protocol) 서버를 구축하며 데이터 포맷 최적화, SQL 기반 쿼리 도입, 도구의 효율적 관리라는 세 가지 핵심 설계를 통해 에이전트의 작업 효율을 극대화했습니다. 결과적으로 이러한 설계 변경은 에이전트의 추론 정확도를 높이는 동시에 토큰 사용량을 줄여 운영 비용을 절감하는 효과를 가져왔습니다. ### 컨텍스트 창 효율성 극대화 * **데이터 포맷 최적화**: JSON은 프로그래밍 방식에는 적합하지만 토큰 소모가 큽니다. 평면적인 데이터에는 CSV(토큰 약 50% 절감)를, 계층 구조가 있는 데이터에는 YAML(약 20% 절감)을 사용하여 동일한 컨텍스트 내에 더 많은 정보를 담았습니다. * **필드 트리밍**: 에이전트에게 불필요한 필드를 기본 출력에서 제거하고 필요한 경우에만 요청하게 함으로써, 동일한 토큰 예산 내에서 레코드 수용량을 최대 5배까지 늘렸습니다. * **토큰 기반 페이지네이션**: 레코드 개수 단위로 데이터를 끊어 보내는 전통적인 방식 대신, 실제 소비되는 토큰량을 기준으로 응답을 제한하여 에이전트의 컨텍스트 창이 예기치 않게 가득 차는 문제를 방지했습니다. ### 단순 조회를 넘어선 SQL 기반 쿼리 도입 * **서버 측 집계**: 에이전트가 수천 개의 로그를 직접 내려받아 트렌드를 분석하는 대신, 서버에서 SQL을 실행하여 요약된 결과만 받도록 개선했습니다. * **비용 및 성능 개선**: SQL을 통해 꼭 필요한 필드만 선택(SELECT)하고 행을 제한(LIMIT)함으로써, 평가 시나리오에서 실행 비용을 약 40% 절감하고 정답률을 높였습니다. * **에이전트 적응력**: AI 에이전트는 SQL 작성에 매우 능숙하며, 이를 통해 컨텍스트 윈도우에 들어갈 데이터를 스스로 세밀하게 제어할 수 있게 되었습니다. ### 도구 비대화 방지 및 관리 전략 * **유연한 도구 설계**: 개별 API 엔드포인트마다 도구를 만드는 대신, 하나의 도구가 여러 유즈케이스를 처리할 수 있도록 스키마를 범용적으로 설계하여 도구의 총 개수를 줄였습니다. * **도구 세트(Toolsets) 분리**: 모든 도구를 한꺼번에 노출하지 않고, 핵심 도구와 특정 워크플로우를 위한 선택적 도구 세트를 구분하여 에이전트의 혼란을 방지하고 컨텍스트 소모를 최소화했습니다. * **도구 계층화**: "어떻게 작업을 수행할지"를 묻는 도구와 실제 동작 도구를 분리하여 검색 효율을 높였습니다. 다만, 이 방식은 레이턴시 증가라는 기회비용이 발생하므로 신중한 적용이 필요합니다. AI 에이전트를 위한 도구를 설계할 때는 인간 사용자를 위한 API 설계와는 다른 접근이 필요합니다. 에이전트가 데이터를 직접 처리하게 두기보다, 서버 측에서 데이터를 가공하고 요약할 수 있는 강력한 쿼리 기능을 제공하고 전송 포맷을 최적화하는 것이 성능과 비용 측면에서 모두 유리합니다.

datadog

Hardening eBPF for runtime security: Lessons from Datadog Workload Protection (새 탭에서 열림)

Datadog은 지난 5년간 수천 개의 환경에서 eBPF 기반의 런타임 보안 제품인 'Workload Protection'을 운영하며 얻은 실전 경험과 교훈을 공유합니다. eBPF는 기존 커널 모듈이나 감사(Audit) 프레임워크보다 안전하고 효율적이지만, 대규모 운영 환경에서는 커널 호환성이나 성능 오버헤드 같은 복잡한 문제들이 발생합니다. 결론적으로 eBPF는 강력한 도구이나, 실제 운영 환경에서 신뢰성을 확보하기 위해서는 단순한 구현을 넘어 정교한 모니터링과 배포 전략이 필수적입니다. **기존 커널 모니터링 기술의 한계와 평가** * **커널 모듈(LKM):** 시스템의 거의 모든 부분을 제어할 수 있는 강력한 권한을 가지지만, 코드 오류가 커널 전체의 크래시로 이어질 수 있어 안정성 측면에서 위험부담이 큽니다. * **전통적인 트레이싱 인터페이스:** inotify, fanotify, kprobes 등은 시스템 내부를 들여다볼 수 있게 해주지만, 전체적인 시스템 활동을 파악하려면 여러 도구를 복잡하게 조합해야 하는 파편화 문제가 있습니다. * **ptrace 및 seccomp-bpf:** 사용자 공간의 프로세스를 추적하는 데 유용하지만, 모든 프로세스 액세스를 감시하기에는 성능 오버헤드가 발생하며 커널 수준의 가시성이 부족합니다. * **Linux Audit 프레임워크:** 가장 널리 사용되는 보안 솔루션이지만, 대량의 이벤트가 발생할 때 시스템 성능에 상당한 영향을 미치는 단점이 있습니다. **보안 제품에 eBPF를 선택한 핵심 이유** * **검증된 안전성:** eBPF 프로그램은 로드되기 전 커널 검증기(Verifier)를 통해 무한 루프나 잘못된 메모리 접근 여부를 정적으로 분석하므로 커널 모듈보다 훨씬 안전합니다. * **통합 가시성:** 프로세스 실행, 파일 시스템 접근, 네트워크 활동 등을 단일 메커니즘으로 모두 추적할 수 있어 시스템 전반에 대한 통합적인 가시성을 제공합니다. * **컨테이너 최적화:** 네임스페이스(Namespace)와 cgroup에 대한 이해도가 높아 컨테이너 환경에서 일관된 모니터링이 가능하며, 특히 CO-RE(Compile Once – Run Everywhere) 도입으로 배포가 쉬워졌습니다. * **강력한 제어 권한:** BPF LSM 기능을 통해 단순한 모니터링을 넘어 시스템 호출을 차단하는 등의 강제 접근 제어(Mandatory Access Control)를 수행할 수 있습니다. **대규모 생산 환경에서의 운영 교훈** * **커널 호환성 유지:** 특정 커널 버전에서는 작동하지만 다른 버전에서는 실패하는 경우를 방지하기 위해 프로그램 로드 및 부착(Attach) 과정을 정교하게 관리해야 합니다. * **성능 비용 관리:** eBPF가 효율적이긴 하지만, 수많은 훅(Hook)이 동시에 실행될 때 발생하는 성능 비용을 지속적으로 측정하고 제어하는 메커니즘이 필요합니다. * **풍부한 데이터 처리:** 캡처된 원시 데이터를 단순히 전달하는 것이 아니라, 보안 분석에 유용하도록 문맥(Context)을 보강하고 정확하게 강화하는 로직이 중요합니다. * **안전한 변경 배포:** 수천 대의 호스트에 영향을 줄 수 있으므로, eBPF 프로그램의 변경 사항을 안전하게 롤아웃하고 문제 발생 시 즉시 감지할 수 있는 시스템을 갖춰야 합니다. **실용적인 제언** eBPF를 도입할 때 "안전하고 성능 저하가 없다"는 마케팅적 수사에만 의존해서는 안 됩니다. 모니터링하려는 워크로드의 특성에 따라 성능 임팩트가 달라질 수 있으므로, 자체적인 성능 모니터링 지표를 구축하고 커널 버전별로 철저한 회귀 테스트를 거치는 것을 추천합니다.

datadog

Scaling real-time file monitoring with eBPF: How we filtered billions of kernel events per minute (새 탭에서 열림)

Datadog은 현대적인 대규모 인프라에서 신뢰할 수 있는 파일 무결성 모니터링(FIM) 시스템을 구축하기 위해 기존의 주기적 스캔이나 `auditd` 방식 대신 eBPF 기술을 채택했습니다. 이들은 커널 수준에서 실시간 가시성을 확보함으로써 프로세스 및 컨테이너 맥락이 포함된 상세한 보안 데이터를 수집하는 데 성공했습니다. 특히 초당 수십억 건에 달하는 방대한 이벤트를 처리하기 위해, 데이터의 94%를 커널 내부에서 미리 걸러내고 에이전트 단위에서 로컬 규칙 검사를 수행하는 2단계 필터링 아키텍처를 통해 시스템 성능 저하 없이 보안 가시성을 극대화했습니다. ### 기존 모니터링 방식의 기술적 한계 * **주기적 파일 시스템 스캔:** 스캔 사이에 발생했다가 복구된 공격자의 변경 사항을 감지할 수 없으며, 파일이 '어떻게', '왜', '누구에 의해' 변경되었는지에 대한 맥락 정보가 부족합니다. * **inotify:** 파일 이벤트와 프로세스 또는 컨테이너 간의 상관관계를 파악하는 데 필요한 시스템 레벨의 컨텍스트를 제공하지 못합니다. * **auditd:** 시스템 부하가 높은 환경에서 과도한 오버헤드가 발생하며, 대규모 환경에서의 확장성 문제가 고질적인 단점으로 지적됩니다. ### eBPF를 활용한 심층 가시성 확보 * **실시간 커널 모니터링:** eBPF를 통해 커널에서 직접 실시간 파일 활동을 관찰함으로써, 파일 변경 사실뿐만 아니라 이를 유발한 프로세스와 컨테이너 정보까지 포함된 풍부한 보안 데이터를 확보했습니다. * **데이터 폭증의 난제:** 모든 인프라에서 발생하는 파일 관련 이벤트가 분당 100억 건을 넘어서며, 이벤트당 약 5KB인 데이터를 모두 전송할 경우 초당 수 테라바이트의 네트워크 트래픽이 발생하는 심각한 규모의 문제에 직면했습니다. ### 에이전트 기반의 로컬 규칙 필터링 * **에지(Edge)에서의 결정:** 수집된 모든 데이터를 백엔드로 전송하는 대신, 각 호스트의 에이전트에서 로컬 보안 규칙에 따라 데이터를 1차 검증합니다. * **트래픽 절감:** 로컬 필터링을 통해 백엔드로 전송되는 데이터를 분당 100억 건에서 약 100만 건 수준으로 획기적으로 줄여, 네트워크 비용과 시스템 자원 소모를 최소화했습니다. ### 커널 내부 프리필터링(In-kernel prefiltering)을 통한 최적화 * **링 버퍼(Ring Buffer) 드롭 방지:** 에이전트가 처리할 수 있는 속도보다 더 빠르게 이벤트가 생성될 경우 데이터 유실이 발생하는데, 이를 막기 위해 처리 로직의 상당 부분을 커널 내 eBPF 프로그램으로 이동시켰습니다. * **2단계 평가 모델:** * **커널 내부 필터링:** 'Approvers'와 'Discarders' 개념을 도입하여, 무관한 시스템 호출(syscall)의 94%를 유저 공간으로 넘기기 전에 커널 단계에서 즉시 폐기합니다. * **유저 공간 평가:** 커널을 통과한 선별된 이벤트에 대해서만 유저 공간에서 상세한 맥락 정보를 결합하고 복잡한 상관관계 분석을 수행합니다. ### 실용적인 제언 대규모 시스템에서 FIM을 구현할 때는 단순한 데이터 수집보다 '불필요한 데이터의 조기 차단'이 성능의 핵심입니다. eBPF를 활용하되 모든 로직을 커널에 넣기보다는, 커널 내에서의 가벼운 필터링과 유저 공간에서의 심층 분석을 결합한 하이브리드 접근 방식을 취하는 것이 확장성과 보안성을 모두 잡는 전략이 될 수 있습니다.

datadog

Replication redefined: How we built a low-latency, multi-tenant data replication platform (새 탭에서 열림)

데이터독(Datadog)은 모놀리식 포스트그레스(Postgres) 데이터베이스의 확장성 한계와 수동 데이터 파이프라인의 복잡성을 해결하기 위해 자동화된 관리형 데이터 복제 플랫폼을 구축했습니다. 이 플랫폼은 체계적인 변경 데이터 캡처(CDC)와 비동기 복제 방식을 통해 데이터 일관성을 유지하면서도 시스템 성능을 비약적으로 향상시켰습니다. 결과적으로 엔지니어링 팀은 인프라 관리의 부담에서 벗어나 안정적이고 낮은 지연 시간으로 대규모 데이터를 다양한 서비스 간에 자유롭게 이동시킬 수 있게 되었습니다. **포스트그레스의 확장성 한계와 데이터 재건축** * 서비스 초기에는 포스트그레스의 ACID 보장과 편의성이 유용했으나, 데이터량이 증가하면서 복잡한 조인 및 집계 쿼리의 응답 시간이 수 밀리초에서 수 초 단위로 급격히 악화되었습니다. * 특정 조직의 메트릭 요약 페이지에서 수십만 개의 행을 조인할 때 P90 지연 시간이 7초에 달했으며, 인덱스 팽창(Bloat)과 VACUUM 작업 부하로 인한 I/O 병목 현상이 발생했습니다. * OLTP 부하와 검색/필터링 부하를 분리하기 위해, 복제 과정에서 데이터를 비정규화(Denormalization)하여 전용 검색 플랫폼으로 전송하는 아키텍처로 전환했습니다. * 이러한 최적화를 통해 페이지 로드 시간을 최대 97% 단축(30초 → 1초)하고, 복제 지연 시간을 500ms 수준으로 유지하는 성과를 거두었습니다. **Temporal을 활용한 복제 파이프라인 프로비저닝 자동화** * Debezium, Kafka, Elasticsearch 등 다양한 기술 스택이 결합된 복제 파이프라인을 수동으로 구축하는 과정은 운영상 큰 부담이 되었습니다. * 포스트그레스의 `wal_level` 설정, 논리적 복제 슬롯 생성, 사용자 권한 관리, Kafka 토픽 매핑 등 반복적이고 오류가 잦은 단계를 Temporal 워크플로우를 통해 모듈화했습니다. * WAL(Write-Ahead Log) 보존 문제를 해결하기 위한 하트비트 테이블 설정부터 싱크 커넥터 배포까지의 모든 과정을 오케스트레이션하여 운영 탄력성을 높였습니다. * 자동화된 플랫폼 덕분에 개발자들은 인프라 설정 대신 혁신에 집중할 수 있게 되었으며, 멀티 테넌트 환경에서도 일관된 파이프라인 관리가 가능해졌습니다. **성능과 확장성을 위한 비동기 복제 전략** * 강한 일관성을 보장하는 동기 복제 대신, 대규모 고처리량 환경에 적합한 비동기 복제 방식을 채택했습니다. * 동기 복제는 네트워크 지연이나 복제본의 응답 상태가 기본 시스템의 성능에 직접적인 영향을 주지만, 비동기 방식은 애플리케이션의 쓰기 성능을 네트워크 지연으로부터 격리합니다. * 장애 발생 시 미세한 데이터 지연이 발생할 수 있는 트레이드오프가 있으나, 이는 확장성과 가용성을 우선시하는 데이터독의 분산 환경에 더 적합한 선택이었습니다. **결론 및 권장사항** 대규모 시스템에서 데이터베이스의 성능 저하를 방지하려면 OLTP와 읽기 전용 검색 워크로드를 분리하는 것이 필수적입니다. 이때 발생하는 복잡한 데이터 이동 문제는 Temporal과 같은 워크플로우 엔진으로 자동화하여 운영 비용을 낮추고, 비동기 복제 모델을 통해 시스템의 전체적인 처리량과 가용성을 확보하는 전략이 권장됩니다.

datadog

Failure is inevitable: Learning from a large outage, and building for reliability in depth at Datadog (새 탭에서 열림)

2023년 3월에 발생한 대규모 장애를 계기로 데이터독(Datadog)은 시스템 가용성에 대한 근본적인 철학을 재정립했습니다. 당시 인프라의 50~60%가 작동 불능 상태에 빠지자 플랫폼 전체가 완전히 멈춘 것처럼 보이는 '정사각형 파형(Square-wave) 실패' 패턴이 나타났으며, 이는 완벽한 데이터 정확성에만 집착하던 기존 설계의 한계를 드러냈습니다. 이에 데이터독은 모든 장애를 막으려는 시도 대신, 극단적인 상황에서도 일부 기능을 유지하며 가치를 제공하는 '우아한 성능 저하(Graceful Degradation)'를 핵심 전략으로 채택했습니다. ### 장애의 교훈: 정사각형 파형 실패의 발견 * **이진법적 실패:** 2023년 3월, 글로벌 보안 업데이트 과정에서 쿠버네티스 노드의 약 절반이 연결을 소실했습니다. 인프라의 절반은 여전히 작동 중이었음에도 불구하고, 사용자 입장에서는 서비스가 아예 응답하지 않거나 데이터가 전혀 보이지 않는 '전부 아니면 전무(All-or-Nothing)' 식의 장애가 발생했습니다. * **정확성 편향의 부작용:** 기존 시스템은 데이터의 정확성을 보장하기 위해 모든 태그와 메트릭이 완전히 처리될 때까지 쿼리 결과 표시를 대기하도록 설계되었습니다. 평상시에는 올바른 선택이지만, 대규모 장애 시에는 일부 데이터 누락이 전체 시스템의 데이터 가독성을 차단하는 결과를 초래했습니다. * **사후 분석의 한계:** 단순히 장애의 트리거(레거시 업데이트 메커니즘)를 제거하는 것만으로는 충분하지 않았습니다. 인증서 만료, 윤초, 설정 오류 등 장애의 원인은 무한하기 때문에, 원인 차단보다는 장애 발생 시 시스템이 어떻게 반응하느냐가 더 중요하다는 점을 깨달았습니다. ### 실패를 위한 설계: 우아한 성능 저하의 원칙 * **복구력 중심의 사고 전환:** 절대 실패하지 않는(Never-fail) 아키텍처는 불가능하다는 것을 인정하고, '더 잘 실패하는(Failing better)' 시스템을 구축하는 데 집중하기 시작했습니다. * **우선순위의 재정립:** 장애 상황에서도 고객의 비즈니스 연속성을 보장하기 위해 세 가지 원칙을 세웠습니다. ① 데이터는 늦더라도 절대 유실되지 않아야 한다. ② 가용한 자원은 실시간 데이터 처리에 우선 할당한다. ③ 아무것도 보여주지 않는 것보다 부정확하더라도 부분적인 결과를 보여주는 것이 낫다. ### 데이터 유실 방지를 위한 영구 흡수 저장소(Persistent Intake) * **메모리 기반 버퍼의 위험성:** 분석 결과, 초기 데이터 흡수(Intake) 단계에서 데이터가 메모리나 로컬 디스크에만 머물러 있다가 노드 장애 시 복구 불가능하게 유실되는 문제가 확인되었습니다. * **디스크 기반 영구 저장:** 데이터 처리 파이프라인의 가장 앞단에 디스크 기반의 복제 저장소를 도입했습니다. 이를 통해 수집 노드가 중단되더라도 데이터가 유실되지 않도록 보장하며, 다운스트림 시스템이 마비되었을 때도 버퍼 역할을 수행하여 데이터 에이전트의 재시도 실패를 방지합니다. * **지연 시간과 안정성의 균형:** 응답 속도를 위해 최적화되었던 기존 방식에서 벗어나, 데이터 수신 확인(Acknowledgment)을 보내기 전에 복제된 저장소에 안전하게 기록하는 구조로 변경하여 신뢰성을 높였습니다. ### 실용적인 결론 및 제언 대규모 시스템을 운영하는 엔지니어링 팀은 시스템의 **신뢰성(Reliability)**을 단순히 '장애가 없는 상태'로 정의해서는 안 됩니다. 시스템의 일부가 마비되더라도 핵심적인 기능은 작동을 멈추지 않도록 설계해야 합니다. 특히 데이터 정확성과 가용성 사이의 트레이드오프를 재검토하여, 장애 시나리오에서는 '완벽한 데이터'보다 '부분적이지만 즉각적인 가시성'을 제공하는 것이 비즈니스 관점에서 훨씬 유리할 수 있음을 명심해야 합니다.

datadog

Inside Husky’s query engine: Real-time access to 100 trillion events (새 탭에서 열림)

Datadog은 매일 100조 개 이상의 이벤트와 수십억 개의 쿼리를 처리하기 위해 3세대 이벤트 저장소인 'Husky'를 구축했습니다. Husky의 쿼리 엔진은 고정된 스키마가 없고 데이터 볼륨이 가변적인 대규모 멀티테넌트 환경에서도 오브젝트 스토리지에 저장된 페타바이트급 데이터를 실시간으로 조회할 수 있도록 설계되었습니다. 이를 위해 시스템은 쿼리 플래너, 오케스트레이터, 메타데이터 서비스, 리더 서비스로 역할을 분산하여 성능과 비용 효율성을 동시에 달성했습니다. ### Husky의 데이터 모델과 주요 쿼리 패턴 Husky는 로그나 네트워크 트래픽과 같이 타임스탬프와 다양한 속성을 가진 '이벤트' 데이터를 저장하며, 서비스별로 상이한 데이터 형태를 유연하게 수용합니다. * **가변적인 스키마 지원:** 테넌트나 사용 사례(로그 vs 네트워크 데이터)에 따라 속성의 종류와 데이터의 크기가 극명하게 달성하더라도 효율적으로 처리할 수 있습니다. * **Needle-in-a-haystack 검색:** 수많은 데이터 중 특정 IP나 에러 메시지, 트레이스 ID 등을 찾아내는 고도로 선택적인 필터링 쿼리를 지원합니다. * **분석형(Analytics-style) 검색:** 특정 기간 동안의 서비스 지연 시간 추이나 지역별 매출 분석과 같이 대규모 데이터를 집계하여 시각화하는 쿼리를 최적화합니다. ### 쿼리 실행의 4단계 아키텍처 Husky의 쿼리 경로는 네 가지 핵심 서비스로 나뉘어 멀티테넌트 환경에서 안정적으로 동작합니다. * **쿼리 플래너(Query Planner):** 모든 쿼리의 진입점으로, 쿼리 유효성 검사 및 최적화를 수행합니다. 통계 데이터를 기반으로 쿼리를 시간 단위의 여러 단계로 분할하고 실행 결과를 최종 병합합니다. * **쿼리 오케스트레이터(Query Orchestrator):** 데이터 저장소의 관문 역할을 하며 메타데이터 조회, 프래그먼트(데이터 파일) 할당, 집계 조율을 담당합니다. 특히 '존 맵(Zone-map) 프루닝'을 통해 불필요한 데이터를 걸러냄으로써 다운스트림 작업량을 평균 30~60% 절감합니다. * **메타데이터 서비스(Metadata Service):** FoundationDB의 프런트엔드로서 데이터 컴팩션 중에도 쿼리 결과의 원자성(Atomicity)을 보장합니다. DB 내부 로직을 추상화하여 전체 쿼리 경로와 분리하는 역할을 합니다. * **리더 서비스(Reader Service):** 실제 오브젝트 스토리지에 저장된 프래그먼트에서 데이터를 읽어 응답을 반환하는 핵심 실행 엔진입니다. ### 리더(Reader) 서비스의 데이터 스캔 최적화 오브젝트 스토리지는 비용이 저렴하지만 읽기 속도가 느리므로, 리더 서비스는 "읽지 않아도 되는 데이터를 스캔하지 않는 것"을 최우선 목표로 삼습니다. * **행 그룹(Row Groups) 구조:** 수백만 행을 가진 대용량 프래그먼트를 '행 그룹' 단위로 물리적으로 배치하여 관리합니다. 이는 쿼리 실행 시 전체 파일을 메모리에 올리는 부담을 줄이고 메모리 부족(OOM) 오류를 방지합니다. * **입출력(I/O) 최소화:** 오브젝트 스토리지에 대한 GET 요청은 비용이 많이 들기 때문에, 쿼리에 꼭 필요한 행 그룹만 선택적으로 가져와 비용 효율성과 응답 속도를 극대화합니다. * **반복자 기반 실행 모델:** Volcano 모델에서 영감을 받은 반복자(Iterator) 방식을 사용하여 데이터를 효율적으로 스트리밍하며 처리합니다. Husky의 사례는 대규모 시계열 이벤트를 처리할 때 고정된 인덱스에 의존하기보다, 메타데이터 기반의 프루닝과 물리적인 데이터 레이아웃 최적화를 통해 오브젝트 스토리지의 한계를 극복할 수 있음을 보여줍니다. 저비용 고성능의 로그 분석 시스템을 설계한다면 데이터의 물리적 구조화와 단계별 쿼리 분산 처리가 핵심이 될 것입니다.

datadog

From hand-tuned Go to self-optimizing code: Building BitsEvolve (새 탭에서 열림)

Datadog은 대규모 인프라에서 Go 언어로 작성된 핵심 함수의 성능을 최적화하여 연간 수십만 달러의 비용을 절감했으며, 이 과정에서 얻은 노하우를 'BitsEvolve'라는 내부 AI 에이전트 시스템으로 자동화했습니다. 단순히 코드 효율을 높이는 것에 그치지 않고, 호출 빈도가 높고 오토스케일링이 적용되는 '핫 패스(Hot-path)' 지점을 데이터 기반으로 식별하여 실제 비즈니스 가치인 비용 절감으로 연결했습니다. 이 글은 전문가의 수동 최적화 기법이 어떻게 대규모 조직을 위한 자동화된 성능 최적화 시스템의 청사진이 되었는지를 상세히 설명합니다. ### 최적화 대상 선정을 위한 세 가지 조건 성능 최적화가 실제 인프라 비용 절감으로 이어지기 위해서는 다음과 같은 조건이 충족되어야 합니다. * **실행 규모:** 함수가 연간 수백만 또는 수십억 번 이상 호출되는 핵심 경로에 있어야 합니다. * **오토스케일링 환경:** CPU 사용량 감소가 단순히 서버의 유휴 시간을 늘리는 것이 아니라, 실제 운영되는 머신 대수의 감소로 이어질 수 있도록 공격적인 오토스케일링이 적용된 서비스여야 합니다. * **유의미한 자원 절감:** 전체 컴퓨팅 자원의 0.5%와 같이 작은 비중을 차지하는 함수라도, 대규모 호출 환경에서는 수만 달러의 비용 절감 효과를 낼 수 있는 지점을 타겟팅합니다. ### 컴파일러 경계 검사 제거를 통한 성능 향상 가장 빈번하게 호출되는 태그 정규화 함수(`isNormalizedASCIITag`)를 최적화하기 위해 하위 수준의 분석을 수행했습니다. * **문제 식별:** Compiler Explorer를 활용해 어셈블리 코드를 분석한 결과, Go 컴파일러가 루프 내부에서 인덱싱 안전성을 확신하지 못해 불필요한 배열 경계 검사(`runtime.panicBounds`)를 반복 실행하는 것을 발견했습니다. * **코드 재구조화:** 컴파일러가 경계 검사를 생략할 수 있도록 루프 구조를 미세하게 재설계했습니다. * **결과:** 함수 실행 속도가 25% 향상되었으며, 이는 서비스 전체 CPU 사용량의 0.75% 감소와 연간 수만 달러의 비용 절감으로 이어졌습니다. ### 관측 데이터 기반의 비관적 코드 개선 모든 예외 상황을 고려하는 방어적인 코드를 실제 데이터에 기반하여 '낙관적'으로 개선함으로써 극적인 성능 향상을 이뤄냈습니다. * **데이터 분석:** 임의의 입력을 처리하는 함수(`NormalizeTagArbTagValue`)가 모든 바이트를 의심하며 검사하고 있었으나, 관측 결과 입력값의 97%가 단순 ASCII였으며 잘못된 UTF-8 데이터는 0.01% 미만이었습니다. * **Fast-path 도입:** 대다수를 차지하는 일반적인 케이스(ASCII)를 즉시 통과시키는 최적화 경로를 추가하여 예외 처리 로직의 부하를 줄였습니다. * **결과:** 해당 함수의 성능을 90% 이상 개선하여 연간 수십만 달러의 인프라 비용을 절감하는 성과를 거두었습니다. ### 수동 최적화에서 에이전틱 자동화 시스템으로의 확장 전문 엔지니어의 수동 최적화는 성과가 크지만 조직 전체로 확장하기 어렵다는 한계가 있습니다. * **BitsEvolve 구축:** 전문가들이 수동 최적화 과정에서 사용한 휴리스틱과 분석 기법을 LLM 기반의 에이전틱 시스템인 'BitsEvolve'의 로직으로 이식했습니다. * **반복 가능한 프로세스:** 특정 전문가의 '영웅적 활약'에 의존하던 방식에서 벗어나, 관측 가능한 데이터를 기반으로 최적화 지점을 찾고 코드를 수정하는 과정을 자동화하고 표준화했습니다. * **지식의 자산화:** 수동으로 해결한 복잡한 최적화 사례들은 AI 시스템이 학습하고 모방해야 할 중요한 데이터 세트이자 벤치마크가 되었습니다. 성능 최적화의 진정한 가치는 단순히 실행 시간을 단축하는 것이 아니라, 관측 데이터(Observability)를 통해 비즈니스 비용과 직결된 병목 구간을 정확히 찾아내는 데 있습니다. 대규모 시스템을 운영하는 엔지니어라면 방어적인 코딩 관습에 의문을 제기하고, 실제 트래픽 특성을 반영한 'Fast-path' 설계와 컴파일러 최적화 원리를 이해함으로써 가시적인 비용 절감을 실현할 수 있습니다.

datadog

Scaling down to speed up: How we improved efficiency of live process metrics by 100x (새 탭에서 열림)

Datadog은 프로세스 및 컨테이너 모니터링 시스템의 실시간 데이터 처리 방식을 '호스트 구독(Host Subscription)' 기반 모델로 전환하여 확장성 문제를 해결했습니다. 사용자가 현재 화면에서 보고 있는 특정 호스트(최대 50개)에 대해서만 2초 간격의 고빈도 수집을 활성화함으로써, 전체 트래픽 볼륨을 100배 줄이고 인프라 비용을 98% 절감하는 성과를 거두었습니다. 이 글은 불필요한 데이터 수집을 최소화하면서도 사용자 경험과 시스템 효율성을 동시에 개선한 기술적 여정을 다룹니다. ## 기존 실시간 데이터 수집의 한계 * **전체 활성화 방식의 비효율성:** 기존에는 테넌트 내 한 명의 사용자만 페이지를 조회해도 해당 테넌트 전체 인프라의 모든 호스트에서 2초 간격의 데이터 수집이 시작되었습니다. 이로 인해 초당 수백만 개의 프로세스 데이터가 유입되는 부하가 발생했습니다. * **수평적 확장 불가능:** 실시간 정렬 기능을 제공하기 위해 테넌트의 모든 데이터를 단일 서버의 메모리에 보관해야 했습니다. 이는 시스템을 수평적으로 확장하는 것을 불가능하게 만들었으며, 서버 사양을 높이는 수직적 확장에만 의존하게 했습니다. * **리소스 낭비:** 실제 사용자가 한 번에 확인하는 프로세스는 약 50개 내외임에도 불구하고, 보이지 않는 수만 개의 프로세스 데이터를 실시간으로 수집하고 처리하는 비효율이 존재했습니다. ## 사용자 가시성 중심의 설계 전환 * **실시간 수집 대상의 최소화:** 사용자가 보고 있는 화면에 노출된 프로세스가 실행 중인 호스트에 대해서만 실시간 모드를 활성화하도록 전략을 수정했습니다. * **데이터 용도 분리 및 정렬 로직 최적화:** 2초 간격의 실시간 데이터는 화면 갱신에만 사용하고, 10초마다 수행되는 정렬 작업에는 일반적인 10초 간격 데이터를 활용하도록 변경했습니다. * **시스템 단순화:** 실시간 뷰와 히스토리 뷰에서 동일한 정렬 로직을 사용할 수 있게 되어 시스템 복잡성이 줄어들었고, 고빈도 메트릭을 메모리에 상주시켜야 할 필요성도 사라졌습니다. ## 호스트 구독 모델 및 필터링 최적화 * **호스트 구독(Host Subscription) 도입:** 사용자가 현재 보고 있는 호스트 목록을 추적하고, 이 상태를 Kafka를 통해 인테이크(Intake) 서비스와 라이브 서버 간에 공유합니다. * **조기 필터링(Early Filtering):** 구독 정보를 바탕으로 데이터 수집 단계(Intake)에서부터 필요한 데이터만 선별하여 처리합니다. 이는 Datadog 에이전트와 백엔드 서버 모두의 부하를 줄이는 핵심 기여를 했습니다. * **성능 개선 결과:** 개념 증명(PoC) 단계에서 이미 라이브 데이터 서버의 메모리 사용량은 85%, CPU 사용량은 33% 감소했으며, 이는 시스템 전체의 안정성 향상으로 이어졌습니다. 대규모 인프라 모니터링 환경에서 모든 데이터를 실시간으로 수집하는 것은 막대한 비용과 확장성 문제를 야기합니다. 사용자의 가시성 범위 내로 수집 대상을 제한하고 데이터의 용도(갱신 vs 정렬)에 따라 수집 빈도를 이원화하는 접근 방식은 리소스 효율성을 극대화하면서도 고성능 실시간 뷰를 제공할 수 있는 실용적인 해결책이 됩니다.

datadog

Evolving our real-time timeseries storage again: Built in Rust for performance at scale (새 탭에서 열림)

데이터독(Datadog)은 급증하는 데이터 볼륨과 고카디널리티(high-cardinality) 워크로드를 처리하기 위해 Rust 기반의 6세대 실시간 시계열 데이터베이스 엔진을 새롭게 설계했습니다. 기존 시스템의 한계를 극복하기 위해 인제스션(Ingestion), 저장, 쿼리 실행 구조를 근본적으로 재구성함으로써 수집 성능은 60배, 쿼리 속도는 최대 5배까지 향상시키는 성과를 거두었습니다. 이 글은 지난 15년간 데이터독이 카산드라에서 시작해 Rust 기반의 전용 엔진에 이르기까지 거쳐온 기술적 진화 과정과 그 과정에서 얻은 교훈을 다룹니다. ### 데이터독 시계열 저장소의 아키텍처 데이터독의 메트릭 플랫폼은 데이터의 효율적인 처리를 위해 실시간 저장소와 인덱스 데이터베이스를 분리하여 운영합니다. * **RTDB (Real-time DB):** `<timeseries_id, timestamp, value>` 형태의 원시 메트릭 데이터를 저장하고 집계하며, 최신 데이터를 실시간으로 서빙합니다. * **인덱스 데이터베이스:** 메트릭 식별자와 태그 정보를 `<timeseries_id, tags>` 형태로 관리합니다. * **데이터 흐름:** 쿼리가 발생하면 상위 서비스가 RTDB와 인덱스 노드에 각각 접속하여 결과를 가져오고, RTDB 노드 내부는 인테이크(Intake), 스토리지 엔진, 스냅샷 모듈, gRPC 쿼리 실행 계층 등으로 구성되어 유기적으로 동작합니다. ### 1세대부터 3세대: 확장성과 운영 효율의 탐색 초기 데이터독은 기성 솔루션을 활용하며 실시간 쿼리 성능과 운영 편의성을 확보하는 데 집중했습니다. * **Gen 1 (Cassandra):** 뛰어난 쓰기 확장성을 제공했으나, 알람 및 분석에 필요한 복잡한 실시간 쿼리를 지원하기 어렵고 대규모 데이터셋 반환 시 효율이 떨어지는 한계가 있었습니다. * **Gen 2 (Redis):** 빠른 읽기 속도와 운영 가시성을 제공했지만, 싱글 스레드 특성상 라이브 트래픽 처리 중 스냅샷 작업이 어려웠고 데이터 직렬화/역직렬화에 따른 CPU 및 메모리 비용이 증가했습니다. * **Gen 3 (MDBM):** `mmap`을 통해 OS 페이지 캐시를 활용하는 메모리 맵 방식의 키-값 저장소를 도입했으나, 대규모 워크로드에서 성능과 정확성 이슈가 발생하며 명시적인 I/O 관리의 필요성을 체감했습니다. ### 4세대와 5세대: 커스텀 엔진과 기능 확장 성능 한계를 돌파하기 위해 범용 DB를 벗어나 전용 스토리지 엔진을 직접 구현하기 시작했습니다. * **Gen 4 (Go 기반 B+ Tree):** Go 언어로 구현된 커스텀 B+ 트리 엔진을 도입하여 '코어당 스레드(thread-per-core)' 모델의 기초를 닦았으며, 처리량과 지연 시간 면에서 큰 진전을 이루었습니다. * **Gen 5 (RocksDB 통합):** 분포 메트릭(distribution metrics)과 DDSketch 타입을 지원하기 위해 RocksDB를 병행 도입했습니다. 하지만 기존 Go 엔진과 RocksDB가 공존하는 구조는 관리가 복잡하고 효율성이 분산되는 결과를 낳았습니다. ### 6세대: Rust 기반의 통합 엔진으로의 전환 파편화된 엔진을 통합하고 성능을 극대화하기 위해 Rust를 선택하여 차세대 시스템을 구축했습니다. * **통합 및 최적화:** 스칼라 값과 스케치 데이터를 모두 처리할 수 있는 단일 엔진을 Rust로 구축하여 언어 차원의 안정성과 고성능 I/O 제어권을 확보했습니다. * **성능 성과:** 이 구조적 변화를 통해 데이터 수집 성능을 60배 높였으며, 피크 시간대 쿼리 속도를 5배 향상시켜 전례 없는 규모의 트래픽을 효율적으로 수용하게 되었습니다. **결론 및 추천** 시스템 규모가 커짐에 따라 범용 데이터베이스나 `mmap`과 같은 추상화 계층은 오히려 성능 병목이 될 수 있습니다. 데이터독의 사례처럼 워크로드의 특성에 맞춰 I/O와 메모리 레이아웃을 직접 제어할 수 있는 전용 엔진을 구축하는 것이 기술적 부채를 해결하고 폭발적인 성장을 뒷받침하는 핵심 전략이 될 수 있습니다. 특히 Rust와 같은 시스템 프로그래밍 언어는 고성능 실시간 시스템을 재설계할 때 강력한 도구가 됩니다.

datadog

How we tracked down a Go 1.24 memory regression across hundreds of pods (새 탭에서 열림)

Go 1.24로의 업그레이드 이후, 새로운 맵 구현인 스위스 테이블(Swiss Tables)에 대한 기대와 달리 일부 서비스에서 메모리 사용량(RSS)이 약 20% 증가하는 현상이 발견되었습니다. 조사 결과, Go 런타임 내부의 메모리 관리 지표는 안정적이었으나 시스템 레벨의 실제 물리 메모리 점유가 늘어난 것으로 확인되었습니다. 이는 Go 1.24에서 진행된 `mallocgc` 함수의 리팩토링 과정에서 발생한 미묘한 메모리 할당자 회귀(Regression) 현상이 원인이었습니다. ### 런타임 지표와 시스템 지표의 불일치 * Go 1.24 업그레이드 후 데이터 처리 서비스의 RSS(Resident Set Size)가 눈에 띄게 증가했으나, Go 런타임 지표와 힙 프로파일상에는 아무런 변화가 기록되지 않았습니다. * 이는 Go 런타임 입장에서는 메모리를 더 사용하고 있지 않다고 판단하지만, 운영체제(Linux) 입장에서는 프로세스가 더 많은 물리 메모리를 점유하고 있는 상태임을 의미합니다. * Kubernetes의 메모리 제한(Limit)이나 OOM 킬러는 시스템 지표인 RSS를 기준으로 작동하기 때문에, 런타임 지표에 나타나지 않는 이러한 증가는 서비스 안정성에 치명적일 수 있습니다. ### 주요 변경 사항에 대한 가설 검증 * 먼저 Go 1.24의 핵심 변화인 '스위스 테이블'과 '스핀 비트 뮤텍스(Spin bit mutex)'를 원인으로 의심하고 실험을 진행했습니다. * `GOEXPERIMENT=noswissmap` 및 `GOEXPERIMENT=nospinbitmutex` 플래그를 사용하여 해당 기능들을 각각 비활성화한 후 빌드하여 배포했으나, 메모리 증가 현상은 해결되지 않았습니다. * 이를 통해 이번 문제는 새로운 기능 자체가 아니라, 런타임의 더 깊은 곳에서 발생한 변화 때문임을 확인했습니다. ### 가상 메모리와 물리 메모리의 매핑 분석 * 리눅스의 `/proc/[pid]/smaps` 파일을 분석하여 프로세스의 메모리 영역별 가상 메모리(Size)와 물리 메모리(RSS)의 차이를 추적했습니다. * 분석 결과, Go 1.23에서는 힙 영역의 RSS가 가상 메모리 크기보다 약 300 MiB 낮게 유지되었으나, Go 1.24에서는 가상 메모리 크기와 RSS가 거의 일치하는 현상이 발견되었습니다. * 결과적으로 Go 1.24의 런타임이 이전 버전보다 가상 메모리를 실제 물리 RAM에 더 공격적으로 할당(Commit)하고 있다는 사실을 밝혀냈습니다. ### mallocgc 리팩토링과 할당자 이슈 * Go 1.24 변경 로그를 정밀 분석한 결과, 메모리 할당의 핵심 로직인 `mallocgc` 함수에 대대적인 리팩토링이 있었음을 확인했습니다. * 이 과정에서 발생한 의도치 않은 로직 변화가 할당된 메모리를 실제 물리적 공간에 매핑하는 방식에 영향을 주어 RSS 상승을 유도한 것으로 파악되었습니다. * 작성자는 이 문제를 Go 개발 팀과 공유하여 원인을 확인했으며, 이는 런타임 리팩토링으로 인한 성능 회귀의 일종으로 결론지어졌습니다. Go 1.24 업그레이드를 고려 중인 팀은 런타임 내부 지표(Heap usage)뿐만 아니라 시스템 레벨의 RSS 지표를 면밀히 모니터링해야 합니다. 비록 메모리 할당자에서 미묘한 RSS 증가가 관측되었지만, 동시에 도입된 스위스 테이블은 대규모 인메모리 맵을 사용하는 서비스에서 수백 기가바이트의 메모리를 절약할 수 있는 잠재력을 가지고 있으므로 서비스 특성에 따른 비교 분석이 필요합니다.

datadog

How Go 1.24's Swiss Tables saved us hundreds of gigabytes (새 탭에서 열림)

Go 1.24에서 도입된 새로운 맵(map) 구현체인 '스위스 테이블(Swiss Tables)'은 대규모 인메모리 데이터를 다루는 서비스에서 획기적인 메모리 절감 효과를 제공합니다. Datadog의 실제 서비스 적용 사례에 따르면, 특정 고부하 환경에서 라이브 힙(Live Heap) 사용량이 500 MiB 감소했으며, 가비지 컬렉터(GOGC)의 영향을 고려할 때 전체 물리 메모리(RSS)는 약 1 GiB까지 절약되었습니다. 이는 Go 1.24의 다른 런타임 오버헤드를 상쇄하고도 남는 수준의 성능 향상을 보여줍니다. **실서비스에서의 메모리 절감 수치** * `ShardRouter` 패키지 내의 `shardRoutingCache`라는 대형 맵에서 약 500 MiB의 라이브 힙 사용량이 감소했습니다. * Go의 기본 GOGC 설정(100)을 기준으로 계산하면, 힙 사용량 감소는 실제 물리 메모리(RSS)에서 약 1 GiB(500 MiB x 2)의 절감으로 이어집니다. * Go 1.24의 다른 회귀 문제(mallocgc 이슈)로 인해 예상되는 400 MiB의 RSS 증가를 고려하더라도, 결과적으로 600 MiB의 순 메모리 감소가 확인되었습니다. **데이터 구조와 메모리 추정** * 해당 맵은 `string`을 키로, `Response` 구조체를 값으로 가집니다. * `Response` 구조체는 `ShardID`(int32), `ShardType`(int), `RoutingKey`(string header), `LastModified`(*time.Time)로 구성됩니다. * 64비트 아키텍처 기준으로 키-값 쌍 하나당 패딩을 포함해 약 56바이트를 차지하며, 서비스 시작 시 대량으로 생성된 후 런타임 중에는 거의 변경되지 않는 특성을 보입니다. **Go 1.23의 버킷 기반 맵 방식과 한계** * 기존 Go 1.23은 8개의 슬롯을 가진 '버킷' 배열로 해시 테이블을 관리했으며, 버킷 수는 항상 2의 거듭제곱으로 유지되었습니다. * 데이터 삽입 시 버킷 내부의 모든 요소를 순차적으로 스캔해야 하므로 CPU 오버헤드가 발생하며, 버킷이 가득 차면 '오버플로우 버킷'을 체이닝 방식으로 추가했습니다. * 평균 로드 팩터(Load Factor)가 13/16(약 81%)을 초과하면 버킷 배열의 크기를 2배로 늘리는 재할당이 발생하는데, 이 과정에서 점진적 복사(Evacuation) 방식을 사용하여 지연 시간을 관리했습니다. **결론 및 권장사항** 대규모 맵 데이터를 메모리에 유지하는 Go 애플리케이션은 Go 1.24로의 업그레이드만으로도 상당한 메모리 효율성 개선을 기대할 수 있습니다. 특히 읽기 중심의 거대 캐시 시스템이나 데이터 라우팅 테이블을 운영하는 경우, 스위스 테이블 기반의 최적화된 메모리 레이아웃이 비용 절감과 성능 향상에 큰 기여를 할 것입니다.

datadog

How we built a real-time, client-side noise suppression library without server dependencies (새 탭에서 열림)

Datadog의 CoScreen 팀은 원격 협업 중 발생하는 배경 소음을 실시간으로 제거하기 위해, 높은 성능과 이식성을 갖춘 오픈소스 라이브러리인 `dtln-rs`를 개발했습니다. 기존의 노이즈 억제 도구들은 WebRTC와의 통합이 어렵거나 고성능 서버 자원을 요구한다는 한계가 있었으나, 이 라이브러리는 클라이언트 측에서 효율적으로 동작하도록 설계되었습니다. 결과적으로 M1 맥북 프로 기준 1초의 오디오를 단 33ms 만에 처리하며, 서버 의존성 없이 다양한 플랫폼에서 고품질의 실시간 소음 제거를 가능하게 합니다. **dtln-rs: 경량화된 실시간 노이즈 억제 라이브러리** * DTLN(Dual-Signal Transformation LSTM Network) 모델을 기반으로 구축된 Rust 언어 기반의 프로젝트입니다. * WebAssembly(WASM), Native Rust, Node.js 네이티브 모듈 등 다양한 타겟으로 빌드할 수 있어 웹 브라우저와 네이티브 앱 모두에 쉽게 통합 가능합니다. * 실제 테스트에서 이웃의 잔디 깎는 기계 소음을 완전히 제거할 정도로 뛰어난 성능을 보여주었으며, 이를 통해 사용자에게 실제적인 가치를 전달합니다. **DTLN 모델의 작동 원리와 효율성** * STFT(단시간 푸리에 변환)를 사용하여 소리를 작은 단위로 분해하고, 주파수별 볼륨(크기 스펙트럼)과 위상(Phase) 정보를 분석합니다. * LSTM(장단기 메모리) 신경망이 포함된 모델을 통해 분석된 데이터 중 어떤 부분이 음성이고 어떤 부분이 소음인지 실시간으로 판단합니다. * 위상 정보와 크기 성분을 모두 활용하는 딥러닝 방식 덕분에 에어컨 소음, 카페 소음, 종이 부스럭거리는 소리 등 다양한 환경에 동적으로 적응하며 즉각적인 감쇠가 가능합니다. **기존 기술의 한계와 개발 배경** * 기존의 고성능 AI 노이즈 제거 모델들은 대부분 강력한 서버 하드웨어를 필요로 하며, 이는 추가적인 지연 시간(Latency)과 막대한 서버 비용을 발생시킵니다. * WebRTC는 널리 쓰이는 오픈소스 기술임에도 불구하고 내장된 노이즈 제거 기능은 구세대 솔루션에 머물러 있어 현대적인 협업 도구들의 품질 요구 수준을 충족하지 못했습니다. * Google 등 대기업이 사용하는 최첨단 모델은 비공개 소스이거나 전용 서버 인프라에 종속되어 있어, 소규모 팀이나 일반 개발자들이 자신들의 앱에 고품질 기능을 구현하기에는 제약이 컸습니다. 실시간 오디오 및 비디오 애플리케이션을 개발하면서 서버 비용 부담 없이 고성능 노이즈 캔슬링 기능을 추가하고 싶다면 `dtln-rs`를 검토해 보시기 바랍니다. 클라이언트 측 리소스를 효율적으로 활용하면서도 WebRTC와 매끄럽게 결합되는 이 라이브러리는 사용자 경험을 한 단계 끌어올리는 실용적인 해결책이 될 것입니다.

datadog

How we built reliable log delivery to thousands of unpredictable endpoints (새 탭에서 열림)

Datadog은 수천 개의 외부 엔드포인트로 로그를 안정적으로 전달하기 위해 물리적인 택배 배송 서비스의 원리를 소프트웨어 아키텍처에 도입했습니다. 특히 Kafka의 엄격한 순차 처리(FIFO) 특성으로 인해 발생하는 '특정 목적지의 장애가 전체 시스템을 마비시키는 문제'를 해결하는 데 집중했습니다. 이를 통해 저지연, 고처리량, 그리고 높은 신뢰성을 보장하는 멀티테넌트 로그 전달 시스템을 구축할 수 있었습니다. ### 로그 포워딩의 역할과 내부 데이터 흐름 * Datadog 로그 포워딩은 내부에서 처리된 JSON 형식의 로그를 ElasticSearch, Splunk, 또는 커스텀 HTTP 엔드포인트와 같은 외부 목적지로 전송하는 디지털 배송 서비스입니다. * 모든 로그 데이터는 내부적으로 Kafka 토픽을 통해 이동하며, 이는 마치 물류 센터의 컨베이어 벨트처럼 작동하여 데이터의 순서를 보장합니다. * 다양한 고객과 목적지로 향하는 로그들이 Kafka 파티션 내에 혼합되어 흐르기 때문에, 이를 목적지별로 다시 그룹화하여 효율적으로 전달하는 과정이 필요합니다. ### 외부 엔드포인트 연동 시 발생하는 병목 현상 * **엔드포인트 불확실성**: 외부 수신 서버는 Datadog의 통제 밖에 있으며, 수시로 응답이 느려지거나 일시적으로 오프라인 상태가 될 수 있습니다. * **Head-of-Line Blocking**: Kafka는 파티션 내의 데이터를 순서대로 처리(Commit)해야 합니다. 만약 특정 목적지의 서버가 응답하지 않아 전송에 실패하면, 해당 파티션에 담긴 다른 모든 목적지의 로그들까지 전송이 중단되는 병목 현상이 발생합니다. * **데이터 유실과 중복의 트레이드오프**: 전송 성공 확인 없이 다음 데이터를 읽으면 유실 위험이 있고, 성공할 때까지 무한히 재시도하면 전체 시스템의 지연 시간(Latency)이 급격히 증가합니다. ### 대규모 멀티테넌시 환경의 설계 제약 * **리소스 효율성**: 수만 개의 목적지마다 별도의 Kafka 토픽을 생성하는 것은 운영 오버헤드와 리소스 낭비가 너무 커서 현실적으로 불가능합니다. * **처리량 최적화**: 매 로그마다 HTTP 요청을 보내는 대신, 택배를 모아서 한 번에 배송하듯 적절한 '배치(Batch)' 처리를 통해 네트워크 오버헤드를 줄여야 합니다. * **보호 메커니즘**: 고객의 엔드포인트가 과부하로 인해 다운되지 않도록 전송 속도를 조절(Rate Limiting)하는 기능이 필수적입니다. ### 실용적인 결론 대규모 분산 시스템에서 외부 시스템과 연동하는 기능을 설계할 때는 **"단일 장애 지점이 전체 시스템에 미치는 영향"**을 최소화하는 격리 전략이 핵심입니다. Kafka와 같은 FIFO 기반 시스템을 사용할 경우, 장애가 발생한 데이터 스트림을 별도의 재시도 경로로 분리하여 정상적인 데이터 흐름이 방해받지 않도록 아키텍처를 구성해야 합니다.