Netflix는 ClickHouse로 매일 5페타바이트의 로그를 수집하며, 초당 1,060만 이벤트를 서브초 쿼리로 처리합니다. 생성된 렉서 기반 로그 핑거프린팅, 커스텀 네이티브 프로토콜 직렬화, 샤딩된 태그 맵이라는 세 가지 최적화가 이 규모를 가능하게 했습니다.
요약
Netflix는 ClickHouse로 매일 5페타바이트의 로그를 수집하며, 서브초 쿼리로 초당 1,060만 이벤트를 처리합니다.
세 가지 최적화가 이 규모를 가능하게 했습니다: 로그 핑거프린팅을 위한 생성된 렉서(8-10배 더 빠름), 커스텀 네이티브 프로토콜 직렬화, 그리고 쿼리 시간을 3초에서 700ms로 줄인 샤딩된 태그 맵입니다.
“Netflix에서는 규모가 모든 것을 좌우합니다.” 엔지니어 Daniel Muino의 말입니다. 과장이 아닙니다.
가장 큰 네임스페이스에서 Netflix의 로깅 시스템은 매일 무려 5페타바이트의 데이터를 수집합니다. 평균적으로 초당 1,060만 개의 이벤트를 처리하고, 피크 시에는 1,250만 개까지 올라가며(“뭔가 이상한 일이 일어나지 않는 한요—그땐 더 높아질 수 있습니다.”라고 Daniel은 말합니다), 각 이벤트의 평균 크기는 약 5 KB입니다. Netflix에는 40,000개가 넘는 마이크로서비스가 있는데, 각 마이크로서비스의 필요에 따라 로그는 2주에서 2년까지 보관됩니다.
그리고 이 시스템은 압도적으로 쓰기 중심이지만, 여전히 초당 500~1,000개의 쿼리를 처리합니다. 이 쿼리들은 엔지니어들이 문제를 디버깅하고, 마이크로서비스를 모니터링하며, 190개 국가의 3억 명이 넘는 구독자를 위한 플랫폼을 안정적으로 운영하는 데 사용됩니다.
대부분의 로깅 플랫폼이라면 감당하기 어려운 규모라고 해도 과언이 아닙니다. 초 안에 검색 가능한 로그, 즉각적으로 느껴지는 쿼리 같은 상호작용성을 가능하게 하려면 적절한 데이터베이스(ClickHouse!)뿐 아니라 세심하게 설계된 일련의 최적화가 필요했습니다.
2025년 7월 Los Gatos에서 열린 ClickHouse 밋업에서 Daniel은 팀이 이를 어떻게 실현했는지, 그리고 Netflix의 페타바이트 규모 로깅을 빠르고 비용 효율적으로 만든 세 가지 돌파구를 공유했습니다.
Netflix의 로깅 구성은 “꽤 단순하고, 엄청 복잡한 건 없습니다.”라고 Daniel은 말합니다. “하지만 이걸 작동하게 하려면 많은 선택을 해야 했습니다.”
로그는 수천 개의 마이크로서비스에서 경량 사이드카를 거쳐 수집 클러스터로 전달됩니다. 짧은 버퍼링 후 데이터는 Amazon S3에 기록되고, Amazon Kinesis에 메시지가 배치되어 다운스트림 처리가 트리거됩니다. 그다음 중앙 허브 애플리케이션이 데이터를 소비하고, 이를 별도의 네임스페이스로 라우팅한 뒤, 적절한 스토리지 계층에 기록합니다.
ClickHouse는 이 시스템의 중심부에서 핫 티어 역할을 합니다. 속도가 중요한 최신 로그를 저장하여 빠른 쿼리와 인터랙티브한 디버깅을 지원합니다. “ClickHouse 덕분에 우리는 이 데이터를 매우 신선한 상태로 제공할 수 있습니다.”라고 Daniel은 말합니다. “중간에 수행하는 모든 버퍼링도 우리에게 큰 영향을 주지 않습니다.”
과거 데이터의 경우 Netflix는 Apache Iceberg를 사용합니다. 이는 더 긴 시간 범위에서 비용 효율적인 장기 저장과 쿼리 기능을 제공합니다. 두 티어 위에는 쿼리 API가 있어 어떤 네임스페이스를 검색할지 자동으로 결정하므로, 엔지니어들은 내부 구조를 신경 쓰지 않고도 통합된 뷰를 얻을 수 있습니다.

ClickHouse를 핫 데이터용으로, Iceberg를 장기 저장용으로 결합한 Netflix의 로깅 아키텍처.
그 결과 거의 즉각적으로 느껴지는 시스템이 만들어졌습니다. 로그는 생성된 뒤 보통 20초 이내에 검색 가능하며, 이는 Netflix의 5분 SLA보다 훨씬 빠릅니다. 어떤 경우에는 엔지니어가 2초 지연으로 라이브 로그를 스트리밍할 수도 있습니다. 이벤트를 클릭해 세부 정보를 보고, JSON 페이로드를 펼치고, 수백만 개의 메시지를 핑거프린트 해시로 그룹화하거나, 주변 로그를 탐색하는 모든 작업을 쿼리가 오래 걸리기를 기다리지 않고 수행할 수 있습니다.
하지만 Daniel의 설명처럼, 이런 수준의 상호작용성은 하루아침에 만들어진 것이 아닙니다. 시스템을 오늘날의 모습으로 만들기 위해 수집, 직렬화, 쿼리라는 세 가지 영역에서 큰 최적화가 필요했습니다.
대규모 OpenTelemetry를 위해 구축된 ClickHouse 기반 오픈 소스 옵저버빌리티 스택을 살펴보세요.
로그를 유용하게 만들기 위해 Netflix는 먼저 유사한 메시지들을 함께 묶어야 합니다. 핑거프린팅이라고 불리는 이 과정은 수백만 개의 거의 동일한 항목을 하나의 패턴으로 축약함으로써 엔지니어들이 노이즈를 걷어내도록 돕습니다. 이것이 없다면 Netflix 규모의 로그 검색은 매우 버거운 일이 될 것입니다.
초기에 팀은 머신러닝 모델을 사용해 로그 메시지를 그룹으로 분류하는 실험을 했습니다. 이론적으로는 가능했지만, 실제로는 리소스를 너무 많이 사용했습니다. “엄청나게 비쌌고, 매우 느렸으며, 제품 전체가 제대로 작동하지 않게 만들었습니다.”라고 Daniel은 회상합니다.
다음으로 팀은 정규 표현식으로 방향을 틀어, 로그 텍스트의 패턴을 매칭하고 값을 일반 토큰으로 바꾸었습니다. 도움이 되긴 했지만, regex는 초당 1,000만 이벤트를 따라잡을 수 없었습니다. “원시 텍스트에서 엔티티를 인식하는 일은 컴파일러가 오래전부터 해오던 일입니다.”라고 Daniel은 설명합니다. “기본적으로 같은 문제이고 같은 해법이 있습니다—렉서가 필요합니다.”
그래서 팀은 JFlex라는 Java 도구를 사용해 최적화된 토크나이저를 생성하는 방식으로 핑거프린팅을 다시 구현했습니다. 런타임에 복잡한 regex를 평가하는 대신, 새 시스템은 패턴을 효율적인 코드로 컴파일합니다. 성과는 엄청났습니다. 처리량은 8-10배 증가했고, 평균 핑거프린팅 시간은 216마이크로초에서 23마이크로초로 줄었습니다. 99퍼센타일에서도 지연 시간은 훨씬 낮았습니다.
“엄청난 성과였습니다.”라고 Daniel은 말합니다. “그리고 사실상 그냥 재작성한 것이었습니다.” 이 재작성으로 시스템의 가장 큰 수집 병목 중 하나가 해소되었고, Netflix는 계속 확장할 여유를 얻게 되었습니다.
로그가 핑거프린팅된 후에도 여전히 초당 수백만 건의 속도로 ClickHouse에 기록되어야 합니다. 여기서 Netflix는 또 다른 병목에 부딪혔습니다. 바로 직렬화입니다.
팀의 첫 구현은 JDBC 배치 삽입에 의존했습니다. 단순하고 익숙했지만 비효율적이기도 했습니다. 준비된 각 statement는 클라이언트가 데이터베이스와 스키마 및 직렬화 세부 사항을 협상하도록 만들었고, 그 오버헤드는 규모가 커질수록 비효율적으로 증가했습니다. “더 잘할 수 있다고 생각했습니다.”라고 Daniel은 말합니다.
그래서 팀은 추상화 스택에서 한 단계 아래로 내려가 ClickHouse의 저수준 Java 클라이언트가 노출하는 RowBinary 형식을 사용했습니다. 이는 데이터를 컬럼별로 수동 직렬화해야 함을 의미했습니다. 맵 길이를 기록하고, DateTime64를 epoch 이후 나노초로 인코딩하고, 그 밖의 여러 특이점을 처리해야 했습니다. Daniel의 말에 따르면 이는 “엄청난 성능 향상”을 가져왔지만, 여전히 충분하지 않았습니다.
“CPU와 할당 프로파일을 봤을 때 정말 너무 거슬렸습니다.”라고 그는 말합니다. “왜 내가 원하는 것보다 더 많은 작업을 하고 있는 걸까? 왜 내가 원하는 것보다 더 많은 메모리를 쓰고 있는 걸까?”
돌파구는 Daniel이 입력 형식 벤치마킹에 관한 ClickHouse 블로그 글을 읽으면서 찾아왔습니다. 네이티브 프로토콜은 일관되게 RowBinary보다 뛰어난 성능을 보였지만, Java 클라이언트는 이를 지원하지 않았습니다. Go 클라이언트만 지원했습니다. “그래서 그냥 Go 클라이언트를 리버스 엔지니어링했습니다.”라고 Daniel은 말합니다.
Netflix는 네이티브 프로토콜을 사용해 LZ4 압축 블록을 생성하고 이를 직접 ClickHouse로 전송하는 자체 인코더를 구축했습니다. 그 결과 CPU 사용량은 줄고 메모리 효율은 높아졌으며, 처리량은 RowBinary와 같거나 어떤 경우에는 더 나아졌습니다.
“아직 완벽하진 않습니다. 제가 막 끝낸 작업이기 때문이죠.”라고 Daniel은 말합니다. “하지만 예전 수준과 동등한 위치에는 와 있고, 최적화할 여지는 아직 많이 남아 있습니다.”
수집과 직렬화가 대부분 쓰기 중심의 과제였다면, 세 번째 병목은 읽기 측면에서 나타났습니다. Netflix의 엔지니어들은 태그에 크게 의존합니다. 태그는 각 로그 이벤트에 추가되는 동적인 키-값 쌍으로, 마이크로서비스, 요청 ID 또는 기타 커스텀 속성으로 필터링할 수 있게 해줍니다. 유용한 만큼 태그는 시스템의 가장 큰 골칫거리 중 하나가 되었습니다.
“커스텀 태그는 우리에게 큰 문제입니다.”라고 Daniel은 말합니다. “사용자들이 일반적으로 자주 사용하는 쿼리 중에서 단연 가장 비용이 많이 드는 쿼리입니다.”
원래 태그는 단순한 Map(String, String)으로 저장되었습니다. 내부적으로 ClickHouse는 맵을 키와 값의 두 개의 병렬 배열로 표현합니다. 모든 조회에는 이 배열들을 선형 스캔해야 했습니다. Netflix 규모에서는 시간당 최대 25,000개의 고유 태그 키와 수천만 개의 고유 값이 존재하므로, 쿼리 성능은 빠르게 저하되었습니다.
Daniel은 이 문제를 ClickHouse의 창시자인 Alexei Milovidov와 논의했고, 그는 LowCardinality types를 사용할 것을 제안했습니다. 키에는 효과가 있었지만 값은 너무 많았기 때문에 절반의 문제만 해결할 수 있었습니다. “값에 LowCardinality를 쓰는 것은 선택지가 아니었습니다.”라고 Daniel은 말합니다.
해법은 놀라울 정도로 단순했습니다. 맵을 샤딩하는 것이었습니다. 태그 키를 해시하여 31개의 더 작은 맵으로 나누면, 쿼리는 모든 키를 스캔하는 대신 올바른 샤드로 바로 이동할 수 있었습니다.
차이는 매우 컸습니다. 한때 3초 걸리던 필터링 쿼리는 1.3초로 줄었습니다. 필터와 프로젝션을 함께 수행하는 쿼리는 거의 3초에서 700밀리초 미만으로 감소했습니다. 두 경우 모두 스캔되는 데이터 양은 5배에서 8배까지 줄어들었습니다.
“이제 예전에는 우리에게 많은 문제를 일으키던 쿼리가 어느 정도는 괜찮아졌습니다.”라고 Daniel은 말합니다. 그리고 Netflix 규모에서는 “그건 아주아주 큰 성과입니다.”라고 덧붙입니다.
이 세 가지 최적화—핑거프린팅 재설계, 직렬화 재작성, 쿼리 구조 재구성—가 합쳐지면서 병목이 제거되었고, Netflix의 로깅 시스템은 어디에 내놓아도 손꼽히는 가장 크고 빠른 ClickHouse 배포 사례 중 하나로 자리 잡았습니다.
이제 이 시스템은 엔지니어의 발목을 잡는 대신, Netflix의 비현실적으로 거대한 규모에서도 가볍고 인터랙티브하게 느껴집니다. 이런 반응성은 장애를 쫓느라 허둥대는 것과 전 세계 수억 명의 시청자를 위해 서비스를 매끄럽게 운영하는 것 사이의 차이를 만들 수 있습니다.
마지막으로 Daniel은 팀의 성공을 기발한 요령보다는 절제된 엔지니어링의 공으로 돌립니다. “핵심은 일을 가장 적게 하도록 어떻게 단순화하느냐에 더 가깝습니다.”라고 그는 말합니다.
팀의 데이터 운영을 혁신하고 싶으신가요? ClickHouse Cloud를 30일 동안 무료로 사용해 보세요.
지금 ClickHouse Cloud 시작하기로 $300 크레딧을 받아보세요. 30일 체험이 끝난 뒤에는 사용량 기반 요금제로 계속 이용하거나, 볼륨 기반 할인에 대해 자세히 알아보려면 문의하기를 이용하세요. 자세한 내용은 요금 페이지를 확인하세요.