대규모 서비스 토폴로지 구축: 아키텍처, 도전 과제, 그리고 얻은 교훈 (새 탭에서 열림)
넷플릭스는 장애 대응과 변경 영향 분석을 위해 실시간 서비스 의존성 지도를 구축했으며, 이를 위해 배치가 아닌 스트리밍 중심 아키텍처를 선택했다. 시스템은 eBPF 네트워크 흐름, IPC 메트릭, 분산 추적 데이터를 물리적으로 분리된 계층에 저장하고, 필요할 때 통합해 제공한다. 대규모 트래픽에서도 안정적으로 동작하기 위해 백프레셔와 분산 집계 파이프라인을 적용했으며, 약간의 지연을 허용하는 대신 데이터 손실과 시스템 장애를 방지했다.
실시간 서비스 토폴로지가 필요한 이유
- 기존의 시간별·일별 배치 방식은 데이터가 생성될 때 이미 오래된 상태가 된다.
- 장애 대응 시 한 시간 전의 의존성 지도는 현재의 장애 원인과 영향 범위를 정확히 보여주기 어렵다.
- 실시간 변경 검증과 장애 분석을 위해 지속적인 데이터 수집과 갱신이 필요하다.
- 넷플릭스의 시스템은 일반적으로 수십 분 이내에 토폴로지 정보를 갱신하는 것을 목표로 한다.
스트리밍 중심 아키텍처
- 여러 리전의 Kafka 스트림에서 네트워크 흐름 데이터를 지속적으로 수집한다.
- IPC 메트릭은 Server-Sent Events(SSE) 형태로 전달하고, 반응형 파이프라인에서 처리한다.
- 배치 처리처럼 완전한 스냅샷을 기다리지 않고, 데이터가 도착하는 즉시 토폴로지를 갱신한다.
- 대규모 트래픽을 처리하면서도 처리 지연이 누적되지 않도록 스트리밍 처리와 부하 제어를 함께 설계했다.
백프레셔를 통한 안정적인 부하 제어
- 단순한 무제한 큐는 트래픽이 급증할 때 메모리를 고갈시키고 인스턴스 장애를 일으킬 수 있다.
- 버퍼가 가득 찼을 때 데이터를 버리는 방식은 연결 정보가 사라져 토폴로지가 불완전해진다.
- 배치 방식은 데이터를 보존할 수 있지만, 장애가 끝난 뒤에야 결과를 확인하게 될 수 있다.
- 백프레셔는 하위 단계의 처리 속도에 맞춰 상위 단계가 자동으로 속도를 줄이는 방식이다.
- 그래프 데이터베이스가 느려지면 Stage 2가 Stage 1에 감속을 요청한다.
- 감속 신호는 Kafka 소비자까지 전파된다.
- Kafka에 데이터가 남아 있으므로 처리 능력이 회복된 뒤 이어서 처리할 수 있다.
- GC 일시정지, 외부 저장소 지연, 트래픽 급증 상황에서도 시스템이 중단되거나 데이터를 대량으로 버리지 않고 점진적으로 느려진다.
- 실시간성이 몇 초 또는 몇 분 늦어지는 대신, 시간 단위로 오래된 데이터나 누락된 토폴로지를 피할 수 있다.
- 반응형 스트림은 전통적인 동기식 처리보다 이해하고 운영하기 어렵지만, 넷플릭스 규모에서는 안정성을 위한 필수 요소로 평가된다.
데이터 소스별 물리적 토폴로지 계층
넷플릭스는 서로 다른 특성을 가진 데이터를 하나의 저장소에 억지로 통합하지 않고, 세 개의 계층으로 분리했다.
- 네트워크 계층
- eBPF 기반 네트워크 흐름 로그를 그래프 데이터베이스에 저장한다.
- 서비스 간 연결을 폭넓게 포착하지만 애플리케이션 수준의 상세한 맥락은 부족하다.
- IPC 계층
- 애플리케이션 메트릭을 별도의 그래프 데이터베이스에 저장한다.
- 엔드포인트 정보가 풍부하지만 계측된 서비스만 포함한다.
- 트레이싱 계층
- 분산 추적 데이터를 Parquet 기반 컬럼형 저장소에 저장한다.
- 실제 요청 경로를 보여주지만 샘플링으로 인해 전체 트래픽을 대표하지 않을 수 있다.
- 각 계층을 물리적으로 분리하면 처리량, 쿼리 패턴, 데이터 발전 주기에 맞춰 독립적으로 최적화할 수 있다.
- 쿼리 시에는 필요한 저장소에 병렬 질의한 뒤 결과를 병합해 통합된 서비스 뷰를 제공한다.
네트워크 중간 장비를 해결하는 분산 집계 파이프라인
네트워크 흐름 로그는 실제 서비스 의존성이 아니라 개별 네트워크 홉만 보여주는 문제가 있다.
- 실제 경로가
App A → 로드 밸런서 → App B라면 흐름 로그에는 두 개의 별도 연결로 기록된다. - 이 데이터를 그대로 시각화하면 서비스 대신 로드 밸런서, NAT 게이트웨이, API 게이트웨이, 프록시 같은 인프라 컴포넌트가 중심에 나타난다.
- 따라서 여러 홉을 분석해 논리적인
App A → App B의존성으로 재구성해야 한다. - 이를 위해 네트워크 계층 수집은 세 단계의 분산 집계 파이프라인으로 구성된다.
Stage 1: 초기 집계
- 네 개 리전의 Kafka에서 흐름 로그를 소비한다.
- 잘못된 흐름 로그를 필터링한다.
- 5분 단위 시간 창으로 데이터를 묶는다.
- 각 시간 창마다 초기 집계 객체를 생성한다.
- 일관성 해싱을 사용해 집계 대상을 분산한다.
- 생성된 집계 결과를 SSE를 통해 Stage 2로 스트리밍한다.
- 이 단계에서는 중간 장비가 포함된 네트워크 홉을 식별하지만, 최종적인 서비스 간 연결은 아직 확정하지 않는다.
대규모 분산 시스템에서 얻은 설계 교훈
- 실시간 처리는 단순히 빠르게 처리하는 문제가 아니라, 느려지는 상황에서도 시스템을 무너지지 않게 만드는 문제다.
- 데이터 손실보다 일시적인 지연을 선택하는 것이 서비스 토폴로지와 장애 분석에는 더 적합할 수 있다.
- 서로 다른 데이터의 특성이 뚜렷하다면 저장소와 처리 계층을 분리하고, 조회 시 통합하는 편이 확장성과 독립적인 최적화에 유리하다.
- 로컬 환경에서 정상 동작하는 구현도 운영 환경에서는 Kafka 지연, 메모리 부족, 트래픽 편중, GC 비용 등으로 쉽게 한계에 도달할 수 있다.
- 따라서 대규모 시스템은 초기 설계뿐 아니라 부하 상황에서의 관찰, 병목 측정, 단계별 최적화 방법론이 중요하다.
실용적으로는 스트리밍 파이프라인을 구축할 때 무제한 버퍼나 무조건적인 데이터 삭제보다 백프레셔를 우선 고려하는 것이 좋다. 또한 서로 다른 품질과 용도를 가진 데이터 소스를 하나의 모델로 통합하기보다, 각 소스에 맞는 저장 계층을 유지하고 조회 단계에서 결합하는 방식이 운영 유연성을 높인다.