LL-HLS는 어떻게 HLS의 지연을 줄이는가
LL-HLS는 Apple이 2019년 WWDC에서 발표한 HLS의 저지연 확장입니다. 기존 HLS가 구조적으로 10초 벽을 깨지 못하는 문제를 해결하기 위해 "세그먼트가 완성되기 전에 부분(Part)을 먼저 전달"하는 접근을 택했습니다.
들어가기 전에
일반 HLS의 지연은 구조적입니다. 6초 세그먼트라면, 인코더가 6초를 모아 세그먼트를 완성하고, 매니페스트에 등록하고, 클라이언트가 폴링으로 확인하고, 다운로드해서 재생합니다. 이 과정을 줄이려면 세그먼트를 잘게 쪼개면 되지만, 그러면 HTTP 요청 수가 폭증하고 CDN 부하가 올라갑니다.
LL-HLS의 해법: 세그먼트는 6초 그대로 유지하되, 그 안을 더 작은 "Part"로 쪼개서 생성되는 족족 서빙합니다. 매니페스트 폴링도 Blocking Reload로 바꿔서 "새 Part가 나올 때까지 서버가 응답을 홀딩"하는 구조입니다.
경쟁 규격인 DASH의 CMAF Low-Latency(LL-CMAF)도 비슷한 접근이지만, Apple 생태계에서는 LL-HLS가 유일한 선택지입니다.
핵심 메커니즘
1. Partial Segments (Parts)
기존 HLS: 세그먼트 완성 → 매니페스트 업데이트 → 클라이언트 다운로드 LL-HLS: 세그먼트 내 Part(200ms~2초) 단위로 즉시 서빙
기존 HLS: |--- 6초 세그먼트 완성 ---|→ 서빙
LL-HLS: |P1|P2|P3|P4|P5|P6|...|→ 각 Part 즉시 서빙
200ms~2초 단위관련 태그:
#EXT-X-PART-INF:PART-TARGET=0.5
#EXT-X-PART:DURATION=0.5,URI="part_001.m4s"
#EXT-X-PART:DURATION=0.5,URI="part_002.m4s"
#EXT-X-PART:DURATION=0.5,URI="part_003.m4s"
...
#EXTINF:6.0,
segment_100.m4s| 태그 | 설명 |
|---|---|
#EXT-X-PART-INF:PART-TARGET=<s> | Part의 목표 길이 (초) |
#EXT-X-PART:DURATION=<s>,URI="..." | 개별 Part 정보 |
#EXT-X-SERVER-CONTROL | 서버 동작 제어 (아래 설명) |
Part가 모이면 기존 세그먼트가 됩니다. 기존 HLS 클라이언트는 완성된 세그먼트만 보므로 하위 호환성이 유지됩니다.
2. Blocking Playlist Reload
기존 HLS는 클라이언트가 매니페스트를 주기적으로 폴링합니다. 새 세그먼트가 없으면 헛 요청이 됩니다.
LL-HLS에서는 클라이언트가 "내가 마지막으로 본 Part 이후의 것을 줘" 라고 요청하면, 서버가 새 Part가 생길 때까지 응답을 홀드합니다.
GET playlist.m3u8?_HLS_msn=100&_HLS_part=3
→ 서버: Part 4가 아직 안 생겼으니 대기...
→ (200ms 후) Part 4 생성됨 → 즉시 응답| 쿼리 파라미터 | 설명 |
|---|---|
_HLS_msn | 요청하는 Media Sequence Number |
_HLS_part | 요청하는 Part 번호 |
_HLS_skip | Delta Update 요청 (YES / v2) |
이걸로 불필요한 폴링이 사라지고, 새 Part가 나오는 즉시 클라이언트에 전달됩니다.
3. Preload Hints
서버가 "다음에 올 Part의 URL"을 미리 알려줍니다:
#EXT-X-PRELOAD-HINT:TYPE=PART,URI="part_004.m4s"클라이언트는 이 URL로 미리 TCP 커넥션을 열어두거나, HTTP/2 PUSH를 활용해 Part가 생성되는 즉시 수신할 수 있습니다.
4. Delta Playlist Update
매니페스트가 길어지면 전체를 받는 것보다 변경분만 받는 게 효율적입니다:
#EXT-X-SERVER-CONTROL:CAN-SKIP-UNTIL=36.0,CAN-BLOCK-RELOAD=YES,PART-HOLD-BACK=1.5
#EXT-X-SKIP:SKIPPED-SEGMENTS=10| 태그 | 설명 |
|---|---|
#EXT-X-SERVER-CONTROL | 서버 기능 선언 (블로킹 리로드, 스킵 가능 여부 등) |
CAN-SKIP-UNTIL | 이 시간 이전의 세그먼트는 Delta에서 생략 가능 |
CAN-BLOCK-RELOAD | Blocking Reload 지원 여부 |
PART-HOLD-BACK | 클라이언트가 라이브 엣지에서 유지할 최소 Part 버퍼 |
지연 시간 비교
| 방식 | 지연 | 핵심 이유 |
|---|---|---|
| 일반 HLS (6초 seg) | 20~30초 | 세그먼트 완성 대기 + 폴링 간격 + 버퍼 |
| 일반 HLS (2초 seg) | 8~12초 | 세그먼트 짧아도 폴링 오버헤드 |
| LL-HLS | 2~4초 | Part 즉시 전달 + Blocking Reload |
| WebRTC (LEB) | < 1초 | 완전히 다른 구조 (UDP) |
LL-HLS의 2~4초 지연 구성:
인코딩 (1 Part 길이): ~0.5초
Part 전송: ~0.1초
CDN 전파: ~0.5초
클라이언트 버퍼 (3 Parts): ~1.5초
─────────────────────────
총: ~2.5초서버 측 요구사항
LL-HLS를 제대로 돌리려면 서버/CDN이 아래를 지원해야 합니다:
| 요구사항 | 설명 |
|---|---|
| Chunked Transfer Encoding | Part가 완성되기 전에 전송 시작 |
| HTTP/2 지원 | 멀티플렉싱으로 Part + Playlist 동시 전송 |
| Blocking Request 처리 | 서버가 응답을 홀드했다가 Part 생성 시 반환 |
| 빠른 매니페스트 갱신 | Part 생성마다 매니페스트 업데이트 (초당 여러 회) |
일반 CDN 캐시는 "완성된 파일"을 캐시하는 데 최적화되어 있습니다. LL-HLS의 Blocking Reload + Chunked Transfer는 CDN에 부하를 줍니다. CDN이 LL-HLS를 네이티브로 지원하는지 확인이 필수입니다.
Tencent Cloud CSS의 LL-HLS 지원
Tencent Cloud CSS에서 LL-HLS를 활성화할 수 있습니다.
설정 위치
CSS Console → Domain Management → [Pull Domain 선택] → Manage → Advanced Configuration → HLS Configuration관련 옵션
| 옵션 | 설명 |
|---|---|
| HLS Type | 일반 HLS / LL-HLS 선택 |
| Part Duration | Part 길이 (초). 보통 0.5~1초 |
| Segment Duration | 기본 세그먼트 길이 (Part의 상위 단위) |
| Playlist Length | 매니페스트에 유지할 세그먼트/Part 수 |
LL-HLS를 켜면 Pull URL은 동일하게 .m3u8이지만, 매니페스트 내에 #EXT-X-PART, #EXT-X-SERVER-CONTROL 등 LL-HLS 태그가 포함됩니다. 기존 HLS 클라이언트는 Part를 무시하고 완성된 세그먼트만 재생하므로 하위 호환성은 유지됩니다.
CSS의 LEB는 WebRTC 기반으로 밀리초 지연을 제공하지만 단방향 전용입니다. LL-HLS는 2~4초 지연이지만 표준 HTTP 인프라에서 동작하므로, 기존 CDN/플레이어 호환성이 더 넓습니다. 지연 1초 미만이 필수면 LEB를, 2~4초면 충분하고 표준 호환성이 중요하면 LL-HLS를 선택하면 됩니다.
일반 HLS vs LL-HLS 비교
| 항목 | 일반 HLS | LL-HLS |
|---|---|---|
| 지연 | 10~30초 | 2~4초 |
| 세그먼트 단위 | 전체 세그먼트 (2~6초) | Part (0.2~2초) + 세그먼트 |
| 매니페스트 갱신 | 클라이언트 폴링 | Blocking Reload (서버 홀드) |
| CDN 부하 | 낮음 | 높음 (Blocking Request + 빈번한 갱신) |
| 서버 요구사항 | 일반 HTTP 서버 | Chunked Transfer + HTTP/2 + Blocking 지원 |
| 하위 호환성 | - | 기존 클라이언트도 재생 가능 (Part 무시) |
| 플레이어 지원 | 모든 HLS 플레이어 | iOS 14+, Safari 14+, hls.js 등 |
마치며
LL-HLS는 "HLS의 구조를 유지하면서 지연만 줄이겠다"는 실용적인 접근입니다. 완전히 새로운 프로토콜을 만든 게 아니라, 기존 HLS 위에 Part + Blocking Reload + Preload Hint를 얹은 것이라 하위 호환성이 살아있습니다.
실무에서 주의할 점:
- CDN 호환성 확인 필수 — Blocking Request를 처리 못하는 CDN에서는 LL-HLS가 동작하지 않습니다
- 인코더/패키저 지원 확인 — Part 단위 출력을 지원해야 합니다
- 비용 증가 — HTTP 요청 수가 일반 HLS 대비 수배~수십 배. CDN 요청 기반 과금이면 비용이 올라갑니다
WebRTC(LEB)와 비교하면 지연에서 지지만, 표준 HTTP 인프라와의 호환성에서는 압도적으로 유리합니다. "기존 CDN 인프라를 바꾸지 않고 지연을 2~4초로 줄이고 싶다"면 LL-HLS가 정답입니다.
참고 자료
- Apple Low-Latency HLS: https://developer.apple.com/documentation/http-live-streaming/enabling-low-latency-http-live-streaming
- HLS 2nd Edition draft: https://datatracker.ietf.org/doc/draft-pantos-hls-rfc8216bis/