Indie Hackers

What Actually Happens When You Press Play on Netflix: A Tour of the Backend

넷플릭스에서 재생을 누르면 벌어지는 일 — 백엔드 둘러보기

넷플릭스의 재생 요청은 Zuul, API 오케스트레이션 계층과 여러 마이크로서비스를 거쳐 계정·라이선스·재생 서버를 확인합니다. 글은 AWS 기반 제어 영역과 Open Connect 기반 콘텐츠 전송을 분리한 구조, 작업에 맞춘 데이터베이스 선택, 이벤트 처리와 장애 대응 방식을 설명합니다.

AI 요약

넷플릭스에서 재생 버튼을 누르면 약 1초 안에 영상이 시작됩니다. 그동안 요청은 로드 밸런서와 API 게이트웨이, 오케스트레이션 계층, 여러 마이크로서비스를 거칩니다. 각 서비스는 계정과 라이선스, 기기 및 네트워크에 맞는 영상 파일, 전송 서버를 확인합니다. 별도 파이프라인은 재생 이벤트를 기록하며, 이런 데이터는 추천과 개인화에도 쓰입니다.

제어 영역과 콘텐츠 전송 영역

넷플릭스 설계의 큰 축은 복잡한 제어 작업과 대용량 데이터 전송을 나누는 데 있습니다. 제어 영역은 AWS에서 여러 서비스와 작은 요청을 처리합니다. 콘텐츠 전송은 Open Connect가 맡아 영상 데이터를 전달합니다. 전자는 복잡한 로직을, 후자는 단순하지만 큰 규모의 데이터 이동을 담당합니다.

재생 요청의 경로

넷플릭스는 80개가 넘는 Zuul 클러스터로 약 100개 백엔드 클러스터의 트래픽을 라우팅합니다. 전체 규모는 초당 100만 건을 훌쩍 넘는 요청입니다. 모든 요청이 Zuul을 지나므로 인증, 라우팅, 보안 규칙과 지표 수집 같은 공통 기능을 한곳에 둘 수 있습니다.

API는 사용자가 하려는 작업을 기준으로 나뉩니다. 각 API가 필요한 마이크로서비스를 오케스트레이션하고, 독립된 호출은 병렬로 실행하며 선행 작업이 필요한 호출은 순서대로 처리합니다. 결과를 모아 기기에 하나의 응답으로 돌려줍니다. TV 앱은 복잡한 백엔드 절차를 알 필요 없이 “이 콘텐츠를 재생해 달라”고 요청하면 됩니다. 기기 종류가 많고 업데이트가 쉽지 않은 환경에서 클라이언트를 단순하게 유지하는 방식입니다.

장애 전파를 막는 장치

수천 개 서비스가 서로 호출하면 일부 요청은 느려지거나 실패합니다. 느린 서비스 하나 때문에 호출자가 계속 기다리면 문제가 다른 서비스로 번질 수 있습니다. 넷플릭스는 Hystrix로 서비스 간 호출에 회로 차단기와 대체 응답을 적용했습니다. 개인화 영화 목록을 만드는 서비스가 실패하면 회로를 열고 인기 가족 영화 같은 일반 목록을 돌려줍니다. 사용자는 개인화가 덜 된 화면을 보지만 홈 화면 전체가 오류로 멈추지는 않습니다. Hystrix는 유지보수 모드이며, 새 프로젝트에서는 resilience4j 같은 라이브러리를 씁니다. 글은 특정 라이브러리보다 장애 시 대체 동작을 미리 설계하는 방식을 강조합니다.

실행 환경과 데이터 저장소

Titus는 Apache Mesos와 AWS를 기반으로 만든 넷플릭스의 컨테이너 플랫폼입니다. 수천 대의 EC2 머신을 관리하고 장기 실행 서비스와 배치 작업을 위해 매주 수백만 개의 컨테이너를 실행합니다.

넷플릭스는 모든 데이터를 한 데이터베이스에 넣지 않습니다. 캐시 계층 EVCache는 Memcached를 기반으로 하며 홈 화면 목록, 평점, 시청 기록처럼 자주 읽거나 미리 계산한 데이터를 저장합니다. 메모리 비용이 커지자 일부 데이터는 SSD로 옮겼습니다. 메모리보다 느리지만 테라바이트당 비용이 낮아지는 절충입니다.

결제에는 MySQL을 씁니다. 구독 기간과 결제 상태, 계정 잔액과 청구 내역에는 트랜잭션과 관계형 데이터베이스의 보장이 필요하기 때문입니다. 대량의 사용자 활동 데이터 등 나머지 데이터 대부분은 Apache Cassandra에 저장합니다. Cassandra는 단일 장애 지점 없이 여러 지역에 복제할 수 있어, 전 세계 클러스터가 지역별 서비스와 백그라운드 복제를 지원합니다.

시청 기록은 계속 쌓이고 많이 시청하는 사용자는 기록도 많이 만듭니다. 데이터 증가로 읽기가 느려지고 저장 비용이 오르자 기록을 두 계층으로 나눴습니다. 최근 데이터는 빠르게 읽고 오래된 데이터는 저렴하게 보관합니다. 데이터가 계속 증가하는 테이블은 오래된 레코드를 보관하거나 압축할 방법을 함께 설계해야 한다는 사례입니다.

이벤트와 개인화

작품 썸네일이 사용자마다 달라지는 기능도 이벤트 처리 파이프라인과 연결됩니다. 넷플릭스는 마이크로서비스에서 발생하는 이벤트를 거의 실시간으로 모으고 처리합니다. 하루에 수조 건의 이벤트와 페타바이트 규모 데이터를 다루며, 일부 데이터는 실시간 개인화에 쓰고 나머지는 배치 분석과 사업 보고에 활용합니다. 처리 결과는 S3, Hadoop, Cassandra 등에 저장됩니다.

글은 이 구조에서 소규모 제품 개발자가 참고할 원칙도 정리합니다. 파일과 미디어처럼 크고 단순한 전송 작업은 핵심 애플리케이션 서버와 분리하고, 공통 요청 처리는 진입 지점에 모읍니다. 장애가 났을 때 보여줄 대체 화면을 미리 정하고, 데이터의 성격에 따라 저장소를 선택합니다. 처음부터 여러 데이터베이스를 도입할 필요는 없지만, 데이터마다 필요한 보장 수준과 읽기 특성을 구분해야 합니다. 이벤트 수집을 일찍 시작하면 이후 분석과 기능 개선에 쓸 재료도 쌓입니다.

Indie Hackers 반응

  • @indie977 — 시청 기록을 나눈 부분이 가장 기억에 남습니다. 최근 기록은 작고 빠르게 유지하고 오래된 기록은 압축하는 방식은 많은 앱이 테이블이 버거워진 뒤에야 고민합니다. 장애 대응 방식에 관한 지적도 좋았습니다. 오류 대신 일반 영화 목록을 보여주는 사례는 성능이 저하된 상태를 미리 설계하라는 좋은 알림입니다.
  • @Angel89 — 훌륭한 설명입니다. 작업마다 다른 데이터베이스를 쓴다는 점이 가장 흥미롭습니다. 저는 테넌트 격리에 행 수준 보안(row-level security)을 적용한 PostgreSQL 하나로 훨씬 작은 멀티테넌트 백엔드를 만들었습니다. 소규모 팀은 현실적으로 언제 저장소를 작업별로 나눠야 하나요? 바꿀 때가 왔다는 첫 신호는 무엇인가요?

원문: Indie Hackers / 번역·요약: Trawling