Netflix Live Origin 분석

원문: Netflix Live Origin — Netflix Technology Blog (2025.12.16)

며칠 전 , Netflix가 자체 라이브 스트리밍을 위해 만든 커스텀 오리진 서버에 대한 기술 블로그 포스팅이 올라왔다. 2024년 타이슨vs폴 복싱 경기에서 동시 6,500만 스트림을 처리한 그 인프라의 핵심 컴포넌트다. 일반적인 CDN 오리진과는 결이 다른, 라이브 전용 설계가 곳곳에 녹아 있어서 분석 해본다.

생각

보통 라이브 스트리밍 오리진이라 하면 패키저가 세그먼트를 밀어 넣고, CDN이 당겨가는 단순한 파일 서버를 떠올린다. AWS라면 MediaPackage가 오리진 역할을 하고, Tencent Cloud라면 StreamPackage가 이 포지션이다. Netflix는 이걸 직접 만들었다. Open Connect(자체 CDN)와 클라우드 인코딩 파이프라인 사이에 앉아서, 단순히 세그먼트를 저장/서빙하는 게 아니라 어떤 세그먼트를 내보낼지 판단하는 브로커 역할까지 한다. "오리진이 똑똑하면 CDN이 편해진다"는 철학이 전체 설계를 관통한다.

전체 아키텍처

Netflix 라이브 파이프라인에서 Live Origin의 위치는:

image.png

Live Origin은 AWS EC2 위에서 동작하는 멀티테넌트 마이크로서비스다. 패키저가 HTTP PUT으로 세그먼트를 밀어 넣고, Open Connect가 HTTP GET으로 가져간다. 프로토콜은 표준 HTTP — 별도의 커스텀 프로토콜 없이 PUT/GET만으로 동작한다.

Tencent Cloud로 매핑하면 StreamPackage가 가장 가까운 포지션이다. StreamLive(인코더) → StreamPackage(패키징+오리진) → CSS(CDN 배포) 구조에서, StreamPackage가 오리진 역할을 한다.

다만 Netflix처럼 "세그먼트 선별 로직"이 오리진에 내장된 구조는 아니고, StreamPackage는 패키징과 DRM에 집중한다.

핵심 설계 1: 멀티 파이프라인 인식 오리진

라이브는 태생적으로 결함이 발생한다. 프레임 드랍, 세그먼트 누락, 타이밍 불연속 — 실시간 인코딩에서 이런 건 "있을 수 있는 일"이다.

여기서 Netflix의 대응은, 이중 인코딩 파이프라인을 독립된 리전에서 돌리고, 오리진이 더 좋은 쪽을 선택한다.

동작 방식:

  1. 두 파이프라인(A, B)이 동일한 세그먼트를 독립적으로 생성

  2. 패키저가 세그먼트를 오리진에 PUT할 때, 미디어의 헬스체크 결과를 메타데이터로 첨부

  3. Open Connect가 GET 요청을 보내면, 오리진이 결정론적 순서로 후보를 확인해서 정상인 쪽을 반환

  4. 극히 드물게 양쪽 다 결함이면, 결함 정보를 다운스트림에 전달해서 클라이언트가 에러 은폐(concealment) 처리

이게 가능한 이유는 클라우드 인코더에 epoch locking(인코더들은 공통된 기준 시각(Epoch Time)을 기준으로 세그먼트 경계를 계산하므로, 서로 다른 인코딩 파이프라인에서도 동일한 세그먼트 번호와 타이밍의 미디어 세그먼트를 생성할 수 있다. 이를 통해 장애 발생 시에도 플레이어는 세그먼트 불연속 없이 다른 파이프라인으로 전환할 수 있다.)을 구현해서, 양쪽 파이프라인이 동일한 세그먼트 번호를 동일한 시점에 생성하기 때문이다.

이 구조의 핵심은 "파이프라인 페일오버를 클라이언트가 아니라 서버에서 처리한다"는 것이다. 클라이언트 복잡도를 줄이는 대신 오리진이 똑똑해지는 트레이드오프.

일반적인 CDN 오리진은 이런 판단을 하지 않는다 — 받은 거 그대로 서빙할 뿐이다.

핵심 설계 2: Open Connect 스트리밍 최적화

Netflix의 Open Connect는 VOD에 최적화된 CDN이었다. 콘텐츠를 미리 OCA(Open Connect Appliance)에 배치하는 구조라, 라이브처럼 "아직 없는 파일을 달라"는 요청 패턴과는 맞지 않았다.

그리하여 넷플릭스가 해결한 문제들:

불필요한 요청 차단

OCA가 세그먼트 템플릿을 알고 있으므로, 아직 존재할 수 없는 시간대의 세그먼트 요청은 오리진까지 올라가기 전에 엣지에서 거부한다.

요청 홀딩 (Hold-Open)

오리진이 "다음 세그먼트"에 대한 요청을 받았을 때, 아직 publish 안 됐으면 404를 돌려보내는 대신 커넥션을 열어두고 세그먼트가 도착하면 바로 응답한다. 이걸로 네트워크 내 불필요한 재요청 트래픽을 크게 줄인다.

밀리초 단위 캐싱

세그먼트가 2초마다 생성되는데, 표준 HTTP Cache-Control은 초 단위다. nginx에 밀리초 단위 캐시 제어를 추가해서 라이브 엣지 근처의 캐시 정합성을 확보했다.

"2초 세그먼트에서 초 단위 캐시는 너무 거칠다"는 인식. 이건 라이브를 해본 사람만 느끼는 문제다. HLS에서 세그먼트 duration 줄이면 매니페스트 업데이트 빈도가 올라가고, 캐시 무효화 타이밍이 까다로워진다.

핵심 설계 3: 스토리지 아키텍처

넷플릭스도 처음에는 그냥 S3를 썼다. VOD에서 쓰던 것과 동일하게. 소규모 이벤트에서는 문제없었는데, 그들은 서비스가 점점 커지면서 라이브의 요구사항이 S3와 맞지 않다는 걸 깨달았다.

Netflix가 정의한 Live Origin 스토리지 요구사항:

요구사항

설명

HA Writes

단일 리전 내 극한의 쓰기 가용성. 500ms 내 쓰기 실패는 버그로 간주

Throughput

수백 MiB/s의 크로스 리전 복제

Large Partitions

MiB 단위 쓰기, 이벤트당 GiB급 누적

Strong Consistency

같은 리전 내 Read-your-write. 퍼블리시 후 1초 이내 읽기 가능

Origin Storm

GiB급 읽기 처리량에서도 쓰기에 영향 없음

S3는 "놀라운 오브젝트 스토리지"이지만 이 요구사항은 "글로벌 저지연 고가용 데이터베이스"에 가까웠다. 그래서 그들은 ..... 직접 만들었다 😂.

최종 스토리지 스택

Live Origin
  └→ KeyValue Storage Abstraction
       ├→ Write: Apache Cassandra (LSM 기반, AZ 장애에도 쓰기 가능)
       └→ Read: EVCache (Memcached 기반 분산 캐시)

쓰기 경로: KeyValue 추상화가 MiB급 페이로드를 청크로 쪼개서 Cassandra에 분산 저장. 각 청크는 멱등하게 재시도/헤징 가능. local-quorum 일관성으로 AZ 하나가 죽어도 쓰기 가능.

읽기 경로: Write-through 캐시로 EVCache(Memcached)를 앞에 둠. 거의 모든 읽기가 캐시에서 처리되므로 200Gbps 이상도 쓰기에 영향 없음.

image.png

결과: P99 쓰기 지연이 기존 S3 기반의 P50과 비슷한 수준까지 내려왔다. 비용은 올라갔지만(SSD 기반 DB니까),

"라이브에서 쓰기 실패 = 세그먼트 유실 = 시청자가 보는 화면이 끊긴다"이므로 비용보다 가용성이 우선.

핵심 설계 4: 스케일링 아키텍처

image.png

2024년 타이슨 vs 폴 경기에서 동시 6,500만 스트림. 이걸 버티려면 오리진 자체가 수평 확장 가능해야 한다.

Netflix는 전통적인 Origin Shield 방식 대신 직접 확장 가능한 오리진을 선택했다. 이유는 엔드투엔드 캐시 일관성 제어가 더 쉽기 때문.

퍼블리시/검색 경로 분리

계층

퍼블리시(쓰기)

CDN 검색(읽기)

EC2

전용 퍼블리시 스택

전용 CDN 스택

스토리지 추상화

KV Write 클러스터

KV Read 클러스터

스토리지 엔진

Cassandra (쓰기)

EVCache (읽기)

CDN 쪽에서 트래픽 폭증이 와도 퍼블리시 경로에 영향이 가지 않는다. 라이브에서 "쓰기가 밀리면 세그먼트가 늦게 나온다"이므로, 이 격리는 생명줄이다.

우선순위 기반 Rate Limiting

시스템에 부하가 걸리면, 요청을 동등하게 처리하지 않는다:

우선순위

트래픽 유형

보호 방법

높음

퍼블리시 (세그먼트 쓰기)

경로 분리

높음

라이브 엣지 검색

우선 처리

낮음

DVR 검색 (과거 구간)

부하 시 503 + 5초 캐시로 억제

낮음

존재하지 않는 세그먼트 요청

404 + TTL로 조기 차단

라이브 엣지 vs DVR 구분은 세그먼트 템플릿 기반으로 판단한다. 템플릿을 오리진 노드 메모리에 캐시해두므로, 데이터스토어 접근 없이도 우선순위를 결정할 수 있다.

image.png

저우선순위 트래픽이 밀릴 때 503 + max-age=5s를 돌려보내서 Open Connect가 5초간 동일 요청을 반복하지 않게 한다. 간단하지만 효과적인 구현이다.

핵심 설계 5: 404 Storm 대응

대규모 라이브 서비스에서는 존재하지 않는 세그먼트에 대한 요청이 순간적으로 폭증하는 경우가 있다. 일반적인 구조라면 이러한 요청이 모두 스토리지까지 전달되어 (404는 Negative caching 하지 않는 편이므로) 불필요한 부하를 유발할 수 있다. 하지만 넷플릭스는 채널과 렌디션 관련 메타데이터를 별도의 컨트롤 플레인 저장소와 인메모리 캐시에 보관한다. 대부분의 조회가 캐시에서 처리되기 때문에, 잘못된 요청이 대량으로 발생하더라도 스토리지 계층으로 부하가 전파되지 않는다. 이는 장애 상황에서도 안정적으로 서비스를 유지할 수 있는 중요한 설계 요소 중 하나다.

아직 생성되지 않은 세그먼트에 대한 요청이 몰리는 "404 Storm" 시나리오. 오리진의 메타데이터 계층 구조를 활용해서 대응한다:

Event → Stream Rendition → Segment

처리 로직:

  1. 이벤트 자체가 없으면 → 즉시 404 (메모리 캐시에서 판단)

  2. 이벤트는 있지만 타이밍이 안 맞으면 → 404 + TTL을 예상 퍼블리시 시간에 맞춰 설정

  3. 세그먼트가 영영 생성 안 되거나 데드라인 초과 → 410 Gone (클라이언트가 재요청 멈춤)

메타데이터는 미디어 데이터와 별도의 컨트롤 플레인 스토어에 저장된다. 이벤트/렌디션 레벨 메타데이터는 인메모리 캐시 적중률이 90%를 넘기므로, 404 폭풍이 와도 스토리지에 부하가 전이되지 않는다.

핵심 설계 6: 캐시 무효화와 오리진 마스킹

캐시 무효화

캐시 키에 버전 번호를 포함시켜서, 버전을 올리면 해당 이벤트의 모든 캐시가 무효화된다. 이벤트 전 테스트 후 네트워크를 깨끗한 상태로 되돌릴 때 사용.

더 세밀한 무효화도 가능하다: "세그먼트 100~150번, 단 인코더 A에서 나온 것만, 리전 X에서 요청된 것만" 같은 조건부 무효화.

오리진 마스킹

특정 파이프라인의 특정 구간 세그먼트를 서빙 대상에서 제외한다. 문제 있는 세그먼트가 발견되면 마스킹을 걸어서 DVR 구간에서도 시청자에게 나가지 않게 보호한다. 수백만 스트리밍 클라이언트를 문제 세그먼트로부터 격리하는 장치.

스트리밍 메타데이터 향상

HTTP 응답 헤더를 통해 스트림 내 이벤트 알림을 전달한다. 광고 시작, 챕터 전환 같은 이벤트를 세그먼트 헤더에 실어 보내는 방식이다.

특징:

  • 알림은 누적형 — 이후 세그먼트에도 계속 포함

  • OCA가 세그먼트를 받을 때 헤더에서 알림 정보를 추출해 인메모리에 저장

  • 클라이언트가 라이브 엣지 뒤에 있더라도 최신 알림을 받을 수 있음

  • 세그먼트뿐 아니라 모든 응답에 알림 정보를 실을 수 있음

Tencent Cloud CSS에서는 SCTE-35 마커를 통해 유사한 역할을 하지만, Netflix는 HTTP 헤더 기반으로 더 범용적인 알림 채널을 만든 셈이다. DASH의 InbandEventStream과 비슷한 역할이지만, 매니페스트가 아닌 세그먼트 응답 헤더에 태우는 방식이 독특하다.

Tencent Cloud 제품 매핑

Netflix의 각 컴포넌트를 Tencent Cloud 제품으로 대응시키면:

Netflix 컴포넌트

역할

Tencent Cloud 대응

Cloud Encoder

라이브 인코딩, 이중화

StreamLive (채널 기반 인코딩, 듀얼 파이프라인)

Packager

세그먼트 패키징

StreamLive Output 또는 StreamPackage 입력

Live Origin

오리진 서버 + 세그먼트 선별

StreamPackage (오리진 역할, 단 선별 로직은 없음)

Open Connect

자체 CDN

CSS CDN 배포

EVCache + Cassandra

오리진 스토리지

해당 없음 (StreamPackage 내부 구현)

Netflix와 Tencent Cloud의 근본적 차이:

  • Netflix는 자체 CDN + 자체 오리진이라 엔드투엔드 제어가 가능

  • Tencent Cloud는 매니지드 서비스 조합이라 각 서비스 경계가 명확하지만, Netflix처럼 오리진이 "세그먼트를 고르는" 수준의 인텔리전스는 서비스 단위로 제공하기 어렵다

  • StreamPackage의 Endpoint 이중화 + Input Failover가 Netflix의 멀티 파이프라인 선택과 유사한 포지션이지만, 구현 깊이가 다르다

마치며

대부분의 라이브 플랫폼은 패키저 뒤에 S3나 일반 오브젝트 스토리지를 두고, CDN이 이를 오리진으로 바라보는 구조에서 출발한다. 사실 이 정도만으로도 상당수 서비스는 충분히 운영할 수 있다. Netflix 역시 처음부터 지금과 같은 구조를 갖고 있었던 것은 아니다.

흥미로운 점은 Netflix가 6,500만 동시 스트림 규모를 처리하는 과정에서 단순히 서버를 더 늘리는 선택을 하지 않았다는 것이다. 세그먼트 생성 지연, 404 폭풍, 오리진 부하 전파, 장애 복구, 페일오버 일관성과 같은 문제를 하나씩 분해하고, 각각에 대해 별도의 시스템적 해법을 만들어냈다. Epoch Locking, Origin Shield, 컨트롤 플레인 분리, 메타데이터 캐싱 같은 설계들은 모두 특정 문제를 해결하기 위한 결과물이다.

이 글을 읽으며 가장 인상 깊었던 부분은 개별 기술 자체보다도 문제를 바라보는 방식이었다. 대규모 시스템에서는 단순히 “동작한다”가 목표가 아니다. 장애가 발생해도 버틸 수 있는지, 비정상 트래픽이 들어와도 다른 계층으로 전파되지 않는지, 특정 컴포넌트가 실패해도 전체 서비스는 계속 동작하는지를 끊임없이 고민한다. Netflix의 아키텍처는 그런 사고방식이 수년간 축적된 결과처럼 보인다.

블로그 글 속 구조도만 보면 모든 것이 단순해 보인다. 하지만 실제 운영 환경에서는 세그먼트 하나가 예상보다 500ms 늦게 생성되는 순간부터 수많은 문제가 연쇄적으로 발생할 수 있다. 결국 대규모 스트리밍 시스템의 본질은 화려한 기술 스택이 아니라, 그런 작은 실패들이 전체 서비스 장애로 이어지지 않도록 만드는 엔지니어링에 있는 것 같다.

그래서 이 글의 진짜 가치는 특정 제품이나 기능 소개가 아니라, Netflix가 어떻게 문제를 정의하고 시스템을 진화시켜 왔는지를 엿볼 수 있다는 점에 있다. 라이브 스트리밍을 다루는 엔지니어라면 규모와 관계없이 한 번쯤은 배워볼 만한 설계 철학이 아닐까 싶다. (물론 실제 구현할 수 있느냐와는 별개의 문제다.)