event-processing

2 개의 포스트

eBPF를 활용한 실시간 파일 모니터링 확장: 분당 수십억 개의 커널 이벤트를 필터링하는 방법 (새 탭에서 열림)

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를 활용하되 모든 로직을 커널에 넣기보다는, 커널 내에서의 가벼운 필터링과 유저 공간에서의 심층 분석을 결합한 하이브리드 접근 방식을 취하는 것이 확장성과 보안성을 모두 잡는 전략이 될 수 있습니다.

Husky: Datadog 규모의 효율적인 컴팩션 (새 탭에서 열림)

Husky는 대규모 관측(observability) 데이터를 처리하기 위해 객체 스토리지 위에 구축된 분산 저장 시스템으로, 매일 수조 개의 이벤트를 효율적으로 관리하는 데 최적화되어 있습니다. 이 시스템은 데이터를 '조각(fragment)' 단위로 저장하고 컴팩션(compaction) 과정을 통해 쿼리 성능과 스토리지 비용 사이의 최적의 균형을 맞추는 것을 핵심 전략으로 삼습니다. 특히 파운데이션DB(FoundationDB)를 활용한 원자적 메타데이터 관리와 병렬 워커 기반의 스캔 구조를 통해 데이터 가용성을 유지하면서도 대규모 분석 쿼리를 신속하게 처리합니다. ## Husky의 쿼리 실행 및 조각화 구조 * Husky는 유입된 이벤트를 조각(fragment)이라 불리는 파일로 묶어 객체 스토리지(S3, GCS 등)에 저장하며, 각 조각에 대한 메타데이터를 별도로 관리합니다. * 쿼리 실행 시 시스템은 메타데이터를 검색하여 관련 있는 조각들을 식별하고, 이를 워커(worker) 풀에 분산하여 병렬로 스캔합니다. * 전체 쿼리 비용은 객체 스토리지에서 가져와야 하는 조각의 수와 해당 파일 내에서 스캔해야 하는 이벤트 수에 비례합니다. * 따라서 효율적인 조회를 위해 파일 수를 제어하는 '스트리밍 머지' 방식의 컴팩션과 쿼리당 스캔 이벤트를 줄이는 데이터 조직화 전략을 사용합니다. ## 컴팩션의 "골디락스(Goldilocks)" 문제 컴팩션은 여러 작은 조각을 하나의 큰 조각으로 병합하는 과정으로, 시스템의 효율성을 결정하는 핵심 요소입니다. Husky는 다음 요소들 사이에서 최적의 균형점(Goldilocks)을 찾습니다. * **파일 크기의 상충 관계:** 파일이 너무 작으면 객체 스토리지 접근 지연 시간과 메타데이터 부하가 커지며, 반대로 너무 크면 쿼리 워커 간의 병렬 처리가 제한되어 대규모 쿼리 속도가 느려집니다. * **컴팩션 비용과 성능:** 컴팩션 작업 자체도 CPU와 객체 스토리지 I/O 비용을 발생시키므로, 작업을 최소화하면서도 쿼리 성능을 높일 수 있는 적정 수준의 병합이 필요합니다. * **데이터 레이아웃 최적화:** 컴팩션 시 시간적 혹은 공간적(태그 등) 유사성에 따라 데이터를 재배치하면 압축률이 향상되고 쿼리 시 스캔해야 할 데이터 범위를 좁힐 수 있습니다. * **벡터화 실행:** Husky 워커는 많은 행을 빠르게 스캔하기 위해 벡터화된 실행(vectorized execution) 방식을 사용하며, 이는 적절한 크기의 조각에서 가장 효율적으로 작동합니다. ## FoundationDB를 통한 원자적 상태 관리 * 데이터 유입이 빈번한 환경에서 사용자가 즉시 데이터를 조회할 수 있도록, Husky는 유입 경로에서 짧은 버퍼링 후 작은 조각들을 빠르게 생성합니다. * 수많은 조각의 메타데이터를 관리하기 위해 트랜잭션 보장이 강력한 FoundationDB를 메타데이터 저장소로 사용합니다. * 컴팩션이 완료되면 FoundationDB의 트랜잭션 기능을 이용해 이전 조각들을 새 조각으로 '원자적(atomic)으로 교체'합니다. * 이를 통해 쿼리 시스템은 컴팩션 진행 중에도 데이터 중복이나 누락 없이 항상 일관된 상태의 테이블을 조회할 수 있습니다. 대규모 시계열 및 관측 데이터를 다루는 시스템을 설계할 때는 무조건적인 데이터 병합보다는 쿼리 패턴과 객체 스토리지의 특성을 고려한 컴팩션 정책이 중요합니다. 특히 메타데이터 계층에서 원자성을 확보하여 데이터 일관성을 유지하고, 병렬 스캔의 이점을 극대화할 수 있는 '적정 크기'의 데이터 블록을 유지하는 설계가 권장됩니다.