카카오엔터테인먼트 영상서비스개발팀이 소녀 리버스의 인코더와 라이브 중계를 만들며 다룬 기술을 정리한 2탄이다. 트랜스코딩 옵션을 정하는 계산식부터 채팅 다시보기를 자막 파일로 실어 보낸 설계, 라이브 투표를 위한 TS 파일 메타데이터 주입, 방송 중 발생한 장애의 원인 규명까지 이어진다. 장애 원인은 HTTP/1.1의 HOL 블로킹이었다.
핵심 포인트- 스트리밍은 트랜스코딩으로 여러 해상도를 만들고, 패키징으로 4초 단위 조각을 내고, CDN에 올리는 세 단계를 거친다.
- 인코딩 옵션은 vmaf 점수에 기준 bitrate와의 차를 곱한 최적화 점수로 정했다.
- 채팅 다시보기는 별도 API 대신 자막 표준 파일로 변환해 플레이어의 자막 재생 로직을 그대로 썼다.
- 라이브 투표는 해당 구간의 모든 TS 파일에 ID3v2 프레임을 PES로 변환해 주입하는 방식으로 시점을 맞췄다.
- 방송 장애의 원인은 HTTP/1.1로 서빙되던 프로필 이미지 서버에서 발생한 HOL 블로킹이었다.
- 채팅량이 평소의 5배를 넘자 이미지 요청 지연이 영상 스트리밍까지 끌어내렸다.
상세 정리- 파이프라인 구성: 인코딩 서버는 트랜스코딩 서버와 패키징 서버로 나뉘고, Airflow가 전체 작업 프로세스를 제어한다.
- Airflow 선택 이유: 웹으로 접근해 조작할 수 있고 DAG 태스크별로 데이터를 재사용하며 로그가 남아 전체 과정을 모니터링하기 적합했다. GCP의 Composer로 환경 구성을 대신했다.
- 트랜스코딩: 원본을 360p부터 1080p까지 네 벌로 만든다. 같은 해상도라도 옵션에 따라 용량과 화질이 달라 옵션값이 핵심이다.
- 옵션 결정 방식: bitrate와 vmaf 그래프를 그려 판단하는데, vmaf만 높이면 평균 bitrate가 올라 CDN 비용이 늘고 저대역폭 환경에서 쓰기 어려워진다.
- 최적화 점수: vmaf 점수에 기준 bitrate와 측정 bitrate의 차를 곱해 낮은 bitrate일수록 가중치가 커지게 했고, 그래프상 면적이 큰 지점을 골라 인코딩했다.
- 패키징: 인코딩된 중간 데이터를 요청받은 포맷으로 엮는 작업이며 video와 audio, 자막 스트림을 다룬다. hls와 dash는 스트리밍용, clean mp4는 내부 검증과 편집용이다.
- 부가 산출물: seek 썸네일은 HTTP 오버헤드를 줄이려 해상도를 낮추고 여러 장을 병합해 제공한다.
- 채팅 다시보기의 통상 방식: 메시지를 DB에 넣고 구간을 꺼내 쓰는 방식은 서버 개발이 추가로 필요하고, 어느 시점에 어떤 데이터를 그릴지 플레이어가 직접 구현해야 한다.
- 선택한 방식: 채팅을 자막 파일에 실어 보내면 플레이어의 검증된 자막 재생 로직을 그대로 쓸 수 있고 파일 기반이라 CDN 캐시에도 유리하다.
- 채팅 패키징 절차: 방송 후 채팅 JSON을 비즈니스 로직으로 필터링하고 편집한 뒤 vtt로 변환하고, 적절한 길이로 잘라 저장한 다음 마스터 플레이리스트에 자막 종류로 등록한다.
- 라이브 투표의 문제: HLS는 사용자마다 2~4초의 재생 시점 차이가 있어 같은 장면에 투표가 뜨게 하려면 시간이 아니라 파일에 맞춰야 했다.
- 주입 절차: ID3v2 프레임을 만들고 PES 헤더를 붙여 패킷을 만든 뒤 188바이트 고정 길이의 TS 패킷으로 쪼갠다. 배수로 떨어지지 않으므로 패딩으로 길이를 맞춘다.
- 플레이어 쪽 처리: TS 디코딩 시 PES 스트림 ID가 Private Stream이면 ID3v2 프레임의 데이터를 꺼내 투표 서버와 연동하고 화면에 노출한다.
- 운영 도구: 세 플랫폼에 흩어진 라이브 채팅을 한 화면에 모으는 웹을 Flutter로 이틀 만에, 접속자와 채팅 수를 보여주는 스코어 보드를 사흘 만에 만들었다.
- 장애 경위: 팀전 라이브 시작 10분 뒤 재생 장애 제보가 올라왔지만 내부 QA에서는 재현되지 않았고 모니터링 인원 10여 명 중 한둘만 간헐적으로 겪었다.
- 장애 대응: 되돌릴 수 없는 상황이고 수정해도 재접속이 있어야 반영되므로 안내 메시지로 가이드하며 지켜보고 원인 분석은 종료 후로 미뤘다.
- 원인 규명: 대부분 HTTP/2로 옮겼는데 프로필 이미지 서버만 HTTP/1.1이었고, 최적화 없이 원본 크기로 불러오다 채팅이 급증하자 HOL 블로킹이 나 영상 스트리밍까지 영향을 받았다.
- 조치: 프로필 이미지 서버 앞에 이미지 최적화와 HTTP/2를 지원하는 캐시 서버를 두고 플레이어가 그 주소로 가져오게 바꿨다.
- 남은 과제 1: 쿠버네티스 자동 확장이 리소스 점유율 기준이라 원하는 타이밍에 맞지 않아 커스텀 메트릭 서버를 만들 예정이다.
- 남은 과제 2: 종단 간 지연이 약 25초라 출연자와 시청자의 소통이 원활하지 않았고, 5~7초 수준의 저지연 스트리밍을 연구 중이라고 밝힌다.
왜 읽나라이브 스트리밍을 직접 구축한다면 인코딩 옵션을 수치로 고르는 법, 부가 데이터를 자막 채널에 얹는 우회, 그리고 무관해 보이는 이미지 서버가 영상까지 끌어내리는 경로를 함께 볼 수 있다.