Zettelkasten

객체 스토리지에 HLS를 쌓으면 세그먼트당 쓰기가 2회여서 요청비가 저장비를 따라잡는다

·수정 1회

요약

  • HLS 라이브는 새 세그먼트가 생길 때마다 미디어 플레이리스트의 새 버전을 내놓아야 한다(RFC 8216 §6.2.1). RFC는 이를 "줄 덧붙이기"로 규정하지만, 객체 스토리지에는 append API가 없어 매번 객체 전체를 다시 PUT하게 된다.
  • 결과적으로 세그먼트 1개당 쓰기 2회가 되고, 렌디션마다 따로 발생한다. 15초 세그먼트라면 5분짜리 녹음 1건에 쓰기 약 42회다.
  • S3 요청 단가는 PUT이 GET의 13배라, 쓰기가 증폭되는 이 구조에서는 요청비가 저장비에 맞먹는 규모까지 올라간다.

본문

왜 세그먼트당 2회가 되나

RFC 8216 §6.2.1은 EXT-X-ENDLIST가 없는 한 서버가 "새 세그먼트를 최소 하나 포함한 플레이리스트의 새 버전"을 타깃 지속시간의 0.5~1.5배 간격으로 계속 제공하도록 요구한다. 세그먼트 길이와 타깃 지속시간이 비슷한 보통 구성에서는 이게 사실상 세그먼트 1개당 플레이리스트 갱신 1회가 된다.

여기까지는 RFC 얘기이고, 쓰기가 2회가 되는 건 스토리지 쪽 사정이다.

  • RFC가 허용하는 변경은 "append lines"와 앞쪽 세그먼트 제거, EXT-X-MEDIA-SEQUENCE 증가다. 로컬 파일시스템이라면 append 한 번으로 끝난다
  • S3·GCS에는 append가 없다. 갱신이 매번 객체 전체 PUT이 된다
  • 슬라이딩 윈도로 오래된 세그먼트를 빼면 EXT-X-MEDIA-SEQUENCE 값이 바뀌어 파일 앞부분이 달라진다. 개념적으로도 append만으로는 불가능하다

즉 append 기반 프로토콜을 append 없는 스토리지에 얹어서 생기는 쓰기 증폭이다. 프로토콜 스펙만 읽으면 안 보이고, 스토리지 API 제약과 겹쳐 놓아야 보인다.

여기에 렌디션 수가 곱해진다. 미디어 플레이리스트는 화질마다 하나이므로 3종이면 세그먼트 1세트당 쓰기 6회다(멀티배리언트 플레이리스트는 처음 한 번만 쓴다).

요청 단가 (S3 ap-northeast-2, Pricing API 조회값)

구분 단가
PUT / COPY / POST / LIST (Tier1) $4.50 / 100만 건
GET 등 (Tier2) $0.35 / 100만 건

PUT이 GET보다 13배 비싸다. 읽기 위주 워크로드에서는 요청비가 눈에 안 띄지만, 쓰기가 증폭되는 구조에서는 저장비와 같은 자릿수까지 올라간다.

실측

음성 전용 HLS(15초 세그먼트, 단일 렌디션)를 쓰는 버킷의 서버 액세스 로그를 바이트 비례로 표본 추출해 세어 보니, PUT 중 .ts가 50.0%, .m3u8이 50.0%였다. 정확히 1:1이다. 플레이리스트 갱신이 전체 쓰기의 절반을 먹고 있다는 뜻이다.

같은 오디오를 녹음 종료 후 한 번에 올리는 다른 파이프라인과 비교하면, 통화 1건당 쓰기가 21회 대 1회로 갈린다.

줄이는 방법

  • 세그먼트 길이를 늘린다. 15초 → 60초면 쓰기가 1/4이 된다. 실시간 재생 지연과 맞바꾸는 선택이다
  • 실시간 재생이 필요 없으면 HLS를 쓰지 않는다. 녹음이 끝난 뒤 단일 파일로 올리면 쓰기가 건당 1회다
  • 저지연 HLS(EXT-X-PART)는 반대 방향이다. 부분 세그먼트마다 플레이리스트를 재발행해야 해서 쓰기가 몇 배로 는다. 비용 관점에서는 최악의 조합이다

비용을 추정하는 법

객체 스토리지의 요청 수는 버킷 크기만 봐서는 안 나온다. 서버 액세스 로깅을 켜 두고 하루치 로그를 바이트 비례로 표본 추출하면 연산별 건수를 충분한 정확도로 추정할 수 있다. 객체 수와 대조해 교차 검증하면 재시도·멀티파트 분까지 드러난다.

관련 노트

참고