apache-druid

4 개의 포스트

netflix원문

똑같은 질문에 두 번 답하지 마세요: 넷플릭스 규모의 Druid를 위한 인터벌 인식 캐싱 (새 탭에서 열림)

넷플릭스는 Apache Druid를 통해 초당 1,500만 건 이상의 이벤트를 처리하며 대규모 실시간 분석을 수행하고 있으나, 대시보드의 롤링 윈도우(Rolling Window) 쿼리가 생성하는 중복 부하 문제를 해결해야 했습니다. 이를 위해 쿼리에서 시간 범위를 분리하여 처리하는 '구간 인식 캐싱(Interval-Aware Caching)' 레이어를 구축하여 Druid의 계산 리소스를 효율화했습니다. 이 시스템은 과거의 안정된 데이터는 캐시에서 불러오고 오직 최신 데이터만 Druid에 요청함으로써, 대규모 트래픽 상황에서도 쿼리 성능을 안정적으로 유지합니다. ### 기존 캐싱 방식의 한계와 문제점 * **롤링 윈도우의 비효율성**: 실시간 모니터링 대시보드는 10~30초마다 "최근 3시간"과 같은 쿼리를 반복해서 보냅니다. 시간 범위가 계속 이동하기 때문에 Druid의 기존 전체 결과 캐시(Full-result cache)는 매번 미스(Miss)가 발생합니다. * **실시간 데이터 캐싱 제한**: Druid는 데이터의 정확성을 위해 실시간 인덱싱 중인 세그먼트의 결과는 캐싱하지 않습니다. 이로 인해 대시보드가 갱신될 때마다 동일한 실시간 세그먼트를 반복해서 스캔하는 낭비가 발생합니다. * **하드웨어 확장의 한계**: 수십 명의 엔지니어가 동일한 대시보드를 볼 때 발생하는 수천 개의 중복 쿼리를 처리하기 위해 단순히 하드웨어를 증설하는 것은 비용 효율성이 매우 낮습니다. ### 구간 인식 캐싱의 핵심 아이디어 * **데이터의 안정성 활용**: 3시간 전의 데이터는 이미 확정되어 변하지 않지만, 최근 1분 내의 데이터는 지연 도착 등으로 인해 변할 수 있습니다. 이 차이를 이용해 오래된 데이터는 캐시에서 즉시 반환하고, 최신 구간만 Druid에 쿼리합니다. * **쿼리 구조와 시간의 분리**: 쿼리문에서 시간 범위(Interval)를 제외한 나머지 구조(필터, 집계 등)를 SHA-256으로 해싱하여 캐시 키로 사용합니다. 이를 통해 서로 다른 시간 범위를 가진 동일한 목적의 쿼리들이 동일한 캐시 항목을 참조할 수 있게 합니다. * **버킷팅(Bucketing) 구조**: 데이터를 쿼리 단위(예: 1분)별로 잘게 쪼개어 'Map-of-Maps' 형태로 저장합니다. 쿼리가 들어오면 필요한 시간 범위에 해당하는 버킷들을 캐시에서 조회하고, 없는 부분만 골라냅니다. ### 지수적 TTL을 통한 효율적인 데이터 관리 * **신선도와 부하의 트레이드오프**: 데이터 파이프라인의 지연 시간을 고려해 최신 데이터에 약 5초의 캐시 유지 시간(TTL)을 부여합니다. 이는 대시보드 사용자에게는 거의 실시간으로 느껴지면서도 Druid의 부하를 대폭 줄여줍니다. * **데이터 연령에 따른 TTL 차등화**: 데이터가 생성된 지 얼마 안 된 버킷은 5~10초의 짧은 TTL을 가집니다. 데이터가 오래될수록 나중에 도착하는 이벤트가 적어지므로, TTL을 지수적으로 늘려 최대 1시간까지 캐시에 보관합니다. * **자동 보정**: 짧은 TTL 덕분에 최신 데이터 구간에서 발생하는 수정 사항은 빠르게 캐시에 반영되며, 오래된 구간은 긴 TTL을 통해 캐시 적중률을 극대화합니다. ### 시스템 구현 및 작동 워크플로우 * **투명한 프록시 구조**: Druid Router 단계에서 요청을 가로채는 외부 서비스 형태로 구현되었습니다. 클라이언트 앱을 수정할 필요 없이 캐싱 기능을 끄거나 켤 수 있습니다. * **쿼리 분해 및 병합**: 1. 들어온 쿼리를 파싱하여 시간 구간을 확인하고 캐시 키(해시)를 생성합니다. 2. 캐시 저장소(예: Redis/Memcached)에서 요청된 구간에 해당하는 연속된 버킷들을 확인합니다. 3. 캐시에 없는 '가장 최신의 불안정한 구간'으로 쿼리 범위를 축소하여 Druid에 요청합니다. 4. 캐시된 결과와 Druid에서 새로 가져온 결과를 병합하여 클라이언트에 반환합니다. 롤링 윈도우 기반의 대규모 대시보드를 운영하는 환경이라면, 모든 데이터를 매번 다시 계산하기보다 이처럼 시간 구간을 나누어 캐싱하는 전략이 Druid 클러스터의 비용 절감과 성능 향상에 매우 효과적입니다. 특히 데이터가 확정되는 속도에 따라 TTL을 다르게 가져가는 '지수적 TTL' 방식은 데이터 정확도와 효율성 사이의 균형을 잡는 유용한 기술적 패턴입니다.

discord4분 읽기큐레이션 요약

Osprey: 규칙 엔진 오픈 소

Discord는 실시간 안전 대응을 위해 개발한 규칙 엔진 Osprey를 ROOST 및 internet.dev 팀과 오픈소스로 공개했다. Osprey는 초당 수천 건의 이벤트를 처리하고, Python 기반 규칙 언어로 탐지 정책을 빠르게 배포하며, 판정 결과와 실행 과정을 추적할 수 있도록 설계됐다. 이를 통해 플랫폼은 새로운 위협에 대응하는 데 필요한 엔지니어링 부담을 줄이고, 탐지 결과를 다음 규칙 개선에 활용할 수 있다. ## Osprey를 개발한 배경과 목표 - 온라인 플랫폼은 스팸, 사기, 악성 사용자 등 유사한 안전 문제를 반복적으로 해결해야 한다. - Osprey는 각 기업이 안전 도구를 처음부터 만들지 않도록 재사용 가능한 규칙 엔진을 제공한다. - 주요 요구사항은 다음과 같다. - **대규모 실시간 처리:** 초당 수천 건의 이벤트를 처리하고 플랫폼 성장에 맞춰 확장 - **신속한 대응:** 표현력 있는 규칙을 작성해 수분 내 적용 - **명확한 판정:** 활동을 안전, 의심, 악성 등으로 판단할 수 있는 결과 제공 - **실행 과정 공개:** 어떤 규칙이 실행됐고 오류가 발생했는지 확인 가능 - **지속적인 학습:** 탐지 결과와 조사 내용을 새로운 규칙 개선에 반영 - **확장성:** 앞으로 등장할 새로운 공격 패턴과 기능을 수용 ## 전체 처리 구조 - Osprey는 플랫폼에서 발생한 **Action**을 입력으로 받는다. - Action은 다음 방식으로 전달할 수 있다. - gRPC를 통한 동기 처리 - 메시지 큐를 통한 비동기 처리 - 입력된 Action은 SML로 작성된 **Rules**를 거친다. - 규칙은 **UDF(User Defined Function)**로 확장할 수 있다. - 실행 과정에서 **Features**와 **Effects**가 생성된다. - 일부 Effects인 **Verdict**는 동기 요청자에게 즉시 판정 결과를 반환한다. - 모든 출력은 Apache Druid 클러스터로 전송되어 조사용 UI에서 검색·분석된다. ## Action: 규칙 엔진의 입력 이벤트 - Action은 Osprey에 전달되는 이벤트이며, 각 이벤트 유형은 고유한 ID와 스키마를 가진다. - 사실상 호출자가 원하는 데이터를 담은 JSON 객체로 구성된다. - 예를 들어 `user_login_attempted` 이벤트에는 사용자 ID, 이름, 이메일, IP 주소 등을 포함할 수 있다. - 이벤트 스키마를 애플리케이션에 맞게 정의할 수 있어 로그인, 메시지 전송, 계정 생성 등 다양한 활동을 처리할 수 있다. ## Rule과 SML 규칙 언어 - Rule은 Osprey의 핵심 구성 요소로, 특정 조건이 충족됐을 때 수행할 조치를 정의한다. - SML(Some Made-up Language)은 Python을 기반으로 한 규칙 언어다. - 기술 지식이 많지 않은 운영·안전 담당자도 작성할 수 있도록 비교적 단순한 문법을 사용한다. - 규칙은 다른 규칙과 데이터를 참조할 수 있어 복잡한 탐지 로직도 구성 가능하다. - 정적 검증을 통해 규칙 작성 방식을 강제할 수 있다. - 변수명 규칙 검사 - 데이터 타입 검사 - 특정 Entity에 적용 가능한 Effect 검사 - 예시에서는 이메일이 특정 값과 일치하면 해당 사용자의 Entity에 `spammer` 라벨을 추가한다. - `EntityJson`으로 사용자 ID를 추출 - `JsonData`로 이메일을 추출 - `Rule`로 스팸 사용자 조건 정의 - `WhenRules`로 조건 충족 시 `LabelAdd` 실행 ## UDF: 규칙 언어를 확장하는 Python 함수 - UDF는 실제 Python으로 작성되며 SML 규칙 어디서든 호출할 수 있다. - `Rule`, `WhenRules`, `JsonData` 등 Osprey의 기본 기능도 UDF로 구현되어 있다. - 사용자가 자체 UDF를 추가해 제품별 기능이나 외부 서비스 연동을 구현할 수 있다. - 예를 들어 외부 머신러닝 서비스에 링크를 전달해 스팸 점수인 `0~1` 범위의 값을 받아 규칙 조건으로 사용할 수 있다. - UDF는 다음과 같은 실행 정보를 정의할 수 있다. - 어떤 기능 범주에 속하는지 - 비동기 실행 여부 - 외부 서비스 접근 방식 - 실행 결과의 타입 - 따라서 규칙 엔진 자체를 수정하지 않고도 새로운 탐지 모델, 데이터 소스, 내부 서비스를 연결할 수 있다. ## Feature: 실행 결과로 생성되는 데이터 - Feature는 Osprey의 전역 네임스페이스에 등록된 변수다. - 모든 Feature는 고유한 이름을 가져야 한다. - 변수명 앞에 `_`를 붙이면 Feature로 외부에 내보내지 않고 현재 파일의 로컬 변수로 유지할 수 있다. - 실행 결과인 Feature는 Druid에 전송·색인된다. - 이후 조사 UI에서 `UserEmail == 'despicable@example.com'`처럼 특정 Feature 값을 기준으로 이벤트를 검색할 수 있다. - 예시의 `UserId`와 `UserEmail`은 모두 Feature다. ## Entity: 효과를 적용할 수 있는 지속적 대상 - Entity는 Feature의 특수한 형태다. - 모든 Entity는 Feature지만, 모든 Feature가 Entity인 것은 아니다. - Discord에서는 사용자, 서버, 이메일처럼 지속적으로 추적할 수 있는 대상을 Entity로 표현한다. - Entity에는 라벨, 분류, 신호 등의 Effect를 적용할 수 있다. - Entity 유형에 따라 적용 가능한 Effect가 달라지며, 이를 정적 검증으로 제한한다. - Osprey UI에서 Entity를 선택하면 해당 대상의 과거 활동과 처리 이력을 확인하는 Entity View로 이동할 수 있다. ## Effect와 Verdict - Effect는 하나 이상의 Rule이 참으로 평가됐을 때 발생하는 결과 또는 조치다. - Effect는 실행 전에 검증되며, 실행이 끝난 뒤 집계해 처리된다. - Entity에 라벨·분류·신호를 부여하는 작업이 대표적인 Effect다. - 동기 Action의 경우 Verdict Effect를 통해 호출자에게 규칙의 판정 결과를 반환할 수 있다. - 이를 활용하면 로그인이나 콘텐츠 게시 요청을 즉시 허용·차단하거나 추가 조사를 요구하는 흐름을 만들 수 있다. ## 실용적인 활용 방향 Osprey는 이벤트 수집, Python 기반 규칙 작성, 외부 탐지 서비스 연동, Druid 기반 조사까지를 하나의 구조로 제공한다. 새로운 위협에 자주 대응해야 하는 플랫폼이라면 규칙을 애플리케이션 코드와 분리하고, 정적 검증과 실행 추적을 갖춘 Osprey 같은 엔진을 활용하는 것이 운영 속도와 투명성을 높이는 방법이 될 수 있다.

원문 읽기(새 탭에서 열림)
toss원문

고객은 절대 기다려주지 않는다: 빠른 데이터 서빙으로 고객 만족도를 수직 상승 시키는 법 (새 탭에서 열림)

토스페이먼츠는 가파른 성장세에 따른 데이터 조회 부하를 해결하기 위해 CQRS 아키텍처를 도입하고 Apache Druid를 중심으로 한 데이터 서빙 환경을 구축했습니다. 초기에는 Elasticsearch와 Druid를 결합하여 대규모 시계열 데이터의 실시간 집계와 검색 성능을 확보했으며, 이를 통해 비용 효율성과 시스템 안정성을 동시에 달성했습니다. 현재는 Druid의 조인 제약과 멱등성 문제를 해결하기 위해 StarRocks를 도입하며, 도메인 간 결합이 자유로운 통합 원장 시스템으로 진화하고 있습니다. ### CQRS와 Apache Druid 도입 배경 * **MSA 전환과 DB 분리:** 서비스 규모가 커지며 모놀리식에서 MSA로 전환했으나, DB가 분산되면서 도메인 간 조인이나 통합 조회가 어려워지는 문제가 발생했습니다. * **명령과 조회의 분리:** 읽기 전용 저장소로 Apache Druid를 선택하여 원장 DB(MySQL)의 부하를 줄이고, 수십억 건의 데이터를 저지연으로 조회하는 CQRS 구조를 설계했습니다. * **Druid의 기술적 이점:** 시계열 데이터 최적화, SQL 지원을 통한 낮은 러닝 커브, 모든 컬럼의 비트맵 인덱스(Bitmap Index)화, 그리고 클라우드 네이티브 구조를 통한 비용 효율성을 고려했습니다. ### 데이터 가공 및 메시지 발행 방식 * **CDC 대신 메시지 발행 선택:** 데이터팀이 도메인 로직을 직접 소유해야 하는 CDC 방식 대신, 각 도메인 팀에서 완성된 데이터를 발행하는 방식을 채택하여 시스템 의존성을 Kafka로 단순화했습니다. * **역정규화 테이블 구성:** 복잡한 수단별 원장 데이터를 조회 친화적인 역정규화 테이블로 변환하여 적재했으며, JSON 필드 단위까지 비트맵 인덱스가 생성되어 효율적인 질의가 가능해졌습니다. ### AWS 환경에서의 비용 및 성능 최적화 * **컴퓨팅과 스토리지 분리:** 고가의 네트워크 스토리지(EBS) 대신 S3를 영구 저장소로 활용하고, 쿼리 수행 시에는 로컬 SSD를 사용하여 성능을 9배 이상 향상했습니다. * **스팟 인스턴스 활용:** 데이터가 S3에 안전하게 보관되는 특성을 이용해 개발/테스트 환경에서 스팟 인스턴스를 적극적으로 사용하여 월 5,000만 원 이상의 클라우드 비용을 절감했습니다. * **고가용성 확보:** 네트워크 스토리지 의존성을 제거함으로써 가용 영역(AZ) 간 분산 배치가 유연해져 시스템의 안정성을 높였습니다. ### Druid 운영의 기술적 도전과 극복 * **파편화 및 멱등성 문제:** 데이터가 시점별로 분산되는 파편화 현상을 해결하기 위해 60초 주기 탐지 프로세스와 자동 컴팩션(Compaction)을 도입했습니다. * **Rollup을 통한 성능 극대화:** 동일 차원의 데이터를 자동 집계하여 저장하는 Rollup 기능을 적용해, 수십 초 걸리던 집계 쿼리 응답 속도를 0.5~1초 내외로 99% 이상 개선했습니다. * **ES 하이브리드 아키텍처:** 단일 ID 기반의 고속 검색은 Elasticsearch가 담당하고, 필터링된 결과의 대규모 집계는 Druid가 처리하도록 역할을 분담해 검색 성능을 안정화했습니다. ### StarRocks 도입을 통한 통합 원장 구축 * **조인 및 멱등성 한계 극복:** Druid의 제한적인 조인 기능과 멱등성 처리의 어려움을 해결하기 위해 StarRocks를 새롭게 도입했습니다. * **도메인 간 데이터 결합:** 결제부터 매입, 정산까지 이르는 전체 라이프사이클을 한눈에 볼 수 있는 통합 원장을 구현하여 비즈니스 요구사항에 유연하게 대응하고 있습니다. **결론적으로** 대규모 트래픽 환경에서는 단순한 DB 분리를 넘어 검색(ES), 시계열 집계(Druid), 그리고 복잡한 조인과 멱등성 보장(StarRocks)이라는 각 도구의 장점을 살린 하이브리드 아키텍처 설계가 필수적입니다. 특히 스토리지와 컴퓨팅을 분리한 구조는 비용 절감뿐만 아니라 운영의 유연성을 확보하는 핵심 전략이 됩니다.

netflix원문

스케일링 뮤즈: 넷플릭스가 조단위 데이터에서 데이터 기반 창의적 인사이트를 제공하는 방법 | 넷플릭스 기술 블로그 | 넷플릭스 기술 블로그 (새 탭에서 열림)

넷플릭스의 내부 데이터 분석 플랫폼인 'Muse'는 수조 건 규모의 데이터를 분석하여 홍보용 미디어(아트웍, 영상 클립)의 효과를 측정하고 창작 전략을 지원합니다. 급증하는 데이터 규모와 복잡한 다대다(Many-to-Many) 필터링 요구사항을 해결하기 위해, 넷플릭스는 HyperLogLog(HLL) 스케치와 인메모리 기술인 Hollow를 도입하여 데이터 서빙 레이어를 혁신했습니다. 이를 통해 데이터 정확도를 유지하면서도 수조 행의 데이터를 실시간에 가깝게 처리할 수 있는 고성능 OLAP 환경을 구축했습니다. ### 효율적인 고유 사용자 집계를 위한 HLL 스케치 도입 * **근사치 계산을 통한 성능 최적화:** 고유 사용자 수(Distinct Count)를 계산할 때 발생하는 막대한 리소스 소모를 줄이기 위해 Apache Datasketches의 HLL 기술을 도입했습니다. 약 0.8%~2%의 미세한 오차를 허용하는 대신 집계 속도를 비약적으로 높였습니다. * **단계별 스케치 생성:** Druid 데이터 수집 단계에서 '롤업(Rollup)' 기능을 사용해 데이터를 사전 요약하고, Spark ETL 과정에서는 매일 생성되는 HLL 스케치를 기존 데이터와 병합(hll_union)하여 전체 기간의 통계를 관리합니다. * **데이터 규모 축소:** 수개월에서 수년 치의 데이터를 전수 비교하는 대신, 미리 생성된 스케치만 결합하면 되므로 데이터 처리량과 저장 공간을 획기적으로 절감했습니다. ### Hollow를 활용한 인메모리 사전 집계 및 서빙 * **초저지연 조회 구현:** 모든 쿼리를 Druid에서 처리하는 대신, 자주 사용되는 '전체 기간(All-time)' 집계 데이터는 넷플릭스의 오픈소스 기술인 'Hollow'를 통해 인메모리 방식으로 서빙합니다. * **Spark와 마이크로서비스의 연계:** Spark 작업에서 미리 계산된 HLL 스케치 집계 데이터를 Hollow 데이터셋으로 발행하면, Spring Boot 기반의 마이크로서비스가 이를 메모리에 로드하여 밀리초(ms) 단위의 응답 속도를 제공합니다. * **조인(Join) 병목 해결:** 복잡한 시청자 성향(Audience Affinity) 필터링과 같은 다대다 관계 연산을 메모리 내에서 처리함으로써 기존 아키텍처의 한계를 극복했습니다. ### 데이터 검증 및 아키텍처 현대화 * **신뢰성 보장:** 아키텍처 변경 전후의 데이터 정합성을 확인하기 위해 내부 디버깅 도구를 활용하여 사전/사후 데이터를 정밀하게 비교 검증했습니다. * **기술 스택 고도화:** React 프런트엔드와 GraphQL 레이어, 그리고 gRPC 기반의 Spring Boot 마이크로서비스 구조를 통해 확장성 있는 시스템을 구축했습니다. * **분석 역량 강화:** 이를 통해 단순한 대시보드를 넘어 이상치 감지(Outlier Detection), 미디어 간 성과 비교, 고급 필터링 등 사용자들의 고도화된 분석 요구를 수용할 수 있게 되었습니다. 대규모 OLAP 시스템을 설계할 때 모든 데이터를 실시간으로 전수 계산하기보다는, HLL과 같은 확률적 자료구조와 Hollow 기반의 인메모리 캐싱을 적절히 조합하는 것이 성능 최적화의 핵심입니다. 특히 수조 건 규모의 데이터에서는 완벽한 정확도와 성능 사이의 트레이드오프를 전략적으로 선택하는 것이 시스템의 유연성을 결정짓습니다.