1장. HLS의 정의와 등장 배경
1.1 스트리밍의 본질과 초기 방식
스트리밍이란
데이터를 모두 다운로드하지 않고, 전달받으면서 동시에 재생하는 방식이다.
초기 스트리밍 기술은 이 개념을 구현하기 위해
“지속적인 연결”을 기반으로 설계되었다.
대표적으로 다음과 같은 프로토콜이 사용되었다.
- RTMP
- RTSP
이 방식의 핵심 구조는 다음과 같다.
클라이언트와 서버가 연결을 유지한 상태에서
데이터를 끊임없이 전달한다
이 구조는 실시간성 측면에서는 효과적이었지만,
인터넷 환경 전체를 고려했을 때는 여러 한계를 가지고 있었다.
1.2 기존 스트리밍 구조의 한계
연결 기반 스트리밍은 다음과 같은 구조적 문제를 가진다.
1) 연결 상태에 대한 강한 의존성
스트리밍이 진행되는 동안 연결이 유지되어야 하므로
네트워크 상태 변화에 매우 민감하다.
- 네트워크 전환 (Wi-Fi → LTE)
- 일시적인 패킷 손실
- 연결 지연
이러한 상황이 발생하면 스트리밍 품질이 즉시 영향을 받는다.
2) 재연결 비용과 복구 문제
연결이 끊어지면 단순히 이어서 재생하는 것이 아니라
다음과 같은 과정이 필요하다.
- 재연결 (handshake)
- 스트림 위치 동기화
- 버퍼 재구성
이 과정은 사용자 입장에서
“영상이 멈추고 한참 뒤에 다시 시작되는 경험”으로 이어진다.
3) 모바일 환경에서의 비효율
연결을 계속 유지하는 구조는 다음과 같은 비용을 발생시킨다.
- 네트워크 인터페이스 지속 활성화
- CPU 사용 증가
- 배터리 소모 증가
특히 모바일 환경에서는 이 문제가 치명적이다.
4) 웹 인프라와의 비호환성
기존 스트리밍은 HTTP 기반이 아니기 때문에:
- CDN 캐싱 활용이 어렵고
- 웹 트래픽과 분리된 별도의 인프라가 필요하다
이는 대규모 서비스 확장에 큰 제약이 된다.
1.3 Apple의 문제 정의
이러한 한계를 해결하기 위해
Apple은 근본적인 질문을 던졌다.
“스트리밍은 반드시 연결을 유지해야 하는가?”
이 질문은 단순한 개선이 아니라
스트리밍의 전제를 뒤집는 접근이었다.
1.4 HLS의 핵심 아이디어
Apple이 제시한 해법은 다음과 같다.
스트리밍을 ‘연결 기반’이 아니라 ‘요청 기반’으로 바꾸자
즉 기존 방식이
- 하나의 연결 위에서 데이터를 흘려보냈다면
HLS는
- 데이터를 여러 단위로 나누고
- 필요할 때마다 요청하여 가져오는 방식으로 바뀌었다
이 변화는 단순한 구현 차이가 아니라
시스템의 성격 자체를 바꾼다.
연결 기반 vs 요청 기반
| 구분 | 연결 기반 | 요청 기반 (HLS) |
|---|---|---|
| 상태 관리 | Stateful | Stateless |
| 데이터 전달 | 지속적 스트림 | 요청 단위 |
| 장애 대응 | 취약 | 유연 |
| 확장성 | 제한적 | 매우 높음 |
이 구조를 한 문장으로 정리하면 다음과 같다.
HLS는 스트리밍을 “데이터 흐름”이 아니라 “리소스 요청”으로 재정의한 기술이다
1.5 HTTP 기반 설계의 의미
HLS는 HTTP/HTTPS 위에서 동작한다.
이 선택은 단순한 구현 편의가 아니라 전략적 결정이다.
1) 웹 인프라와의 완전한 통합
- 기존 웹 서버 사용 가능
- CDN 캐싱 활용 가능
- 별도 프로토콜 필요 없음
즉, 스트리밍이 웹 트래픽의 일부가 된다
2) Stateless 구조
각 요청은 독립적으로 처리된다.
- 연결 유지 불필요
- 실패 시 다음 요청으로 복구 가능
이는 네트워크 환경 변화에 강한 구조를 만든다.
3) 네트워크 및 방화벽 친화성
HLS는 일반 웹 요청과 동일하게 동작한다.
- 포트 80 / 443 사용
- HTTP GET 요청 기반
따라서 대부분의 네트워크 환경에서 자연스럽게 허용된다.
여기서 중요한 표현은 다음과 같다.
HLS는 방화벽을 “우회하는 기술”이 아니라
애초에 차단되지 않는 방식으로 설계된 기술이다
1.6 시장과 기술의 교차점
HLS는 기술적 해결책이면서 동시에
플랫폼 전략의 일부였다.
당시 스트리밍 시장은
Adobe의 Flash 기반 기술이 지배하고 있었다.
Flash 기반 구조는:
- RTMP 중심
- 플러그인 의존
- 데스크탑 환경 중심
이에 대해
Apple은 다음과 같은 방향을 선택했다.
Apple의 전략
- iPhone에서 Flash 미지원 선언
- HTML5 기반 웹 생태계 선택
- HTTP 기반 스트리밍 도입
이 선택은 단순한 기술 교체가 아니라
스트리밍의 권력 구조를 바꾸는 결정이었다.
결과적으로:
스트리밍은 플러그인 기술에서 웹 표준 기술로 전환되었다
1.7 스트리밍 패러다임의 전환
HLS의 등장 이후 스트리밍은 다음과 같이 변화했다.
Before
- 연결 중심
- 특수 프로토콜
- 환경 의존적
After
- 요청 중심
- HTTP 기반
- 웹과 완전히 통합
이 변화의 핵심은 다음 한 문장으로 요약된다.
스트리밍은 더 이상 특수한 기술이 아니라, 웹 기술의 일부가 되었다
1.8 HLS의 설계 목표와 구조적 한계
HLS는 특정 목표를 기반으로 설계되었다.
✔ 설계 목표
- 안정성
- 확장성
- 네트워크 호환성
❗ 그 결과 발생하는 한계
이 구조는 자연스럽게 다음과 같은 특성을 만든다.
- 데이터가 준비된 이후 전달됨
- 요청 단위로 처리됨
👉 결과:
구조적으로 지연(Latency)이 발생한다
이 부분은 매우 중요하다.
HLS는 초저지연을 위해 만들어진 기술이 아니다
→ 안정성과 확장성을 우선한 기술이다
2장. 왜 동영상을 잘게 나누는가
2.1 동영상을 “쪼개서” 전달한다는 것의 의미
HLS는 동영상을 하나의 파일로 다루지 않는다.
대신 다음과 같이 처리한다.
동영상을 짧은 시간 단위의 조각으로 나누고, 이를 순차적으로 전달한다
이 개념을 쉽게 이해하려면 이렇게 생각하면 된다.
HLS는 방송 영상을
한 편의 긴 영화 파일이 아니라
짧은 영상 클립들의 집합으로 다룬다.
예를 들어 10초짜리 영상이라면:
- 0~2초
- 2~4초
- 4~6초
- 6~8초
- 8~10초
이렇게 여러 개의 조각으로 나뉜다.
플레이어는 이 조각들을:
순서대로 하나씩 다운로드하면서 동시에 재생한다
즉, 전체 영상을 한 번에 받는 것이 아니라
조각 단위로 이어 붙이면서 재생하는 구조다.
2.2 왜 굳이 잘게 나누는가
이 구조는 단순한 구현 방식이 아니라
스트리밍의 문제를 해결하기 위한 핵심 설계다.
2.2.1 네트워크 불안정에 대한 대응
인터넷 환경은 항상 안정적이지 않다.
- 속도가 순간적으로 떨어질 수 있고
- 패킷 손실이 발생할 수 있으며
- 연결이 일시적으로 끊길 수도 있다
만약 하나의 큰 파일을 전송하는 구조라면:
- 다운로드 중단 시 전체 흐름이 끊기고
- 재시작 비용이 매우 크다
반면 HLS처럼 조각 단위로 나누면:
- 일부 조각만 실패
- 다음 조각부터 다시 요청 가능
즉,
문제를 “전체 실패”에서 “부분 실패”로 축소한다
이것이 HLS가 안정적인 이유다.
2.2.2 요청 기반 구조와의 자연스러운 결합
HLS는 HTTP 요청 기반 구조다.
이 구조에서는:
- 요청 → 응답 → 종료
- 다시 요청 → 응답 → 종료
이 흐름이 반복된다.
동영상을 조각으로 나누면 이 구조에 딱 맞는다.
- 조각 하나 = 요청 하나
- 요청 단위로 처리 가능
즉,
조각 단위 구조는 HTTP의 특성과 정확히 맞물린다
2.3 적응형 비트레이트 (ABR)의 필요성
네트워크는 항상 일정하지 않다.
- 어떤 순간에는 10Mbps
- 어떤 순간에는 2Mbps
이 상황에서 항상 고화질 영상을 보내면:
- 버퍼링 발생
- 재생 끊김 발생
반대로 항상 저화질이면:
- 화질 낭비
- 사용자 경험 저하
이 문제를 해결하기 위해 등장한 개념이
적응형 비트레이트 (Adaptive Bitrate, ABR)
이다.
2.4 ABR이 가능한 이유
ABR은 HLS의 “조각 구조” 덕분에 가능하다.
핵심은 이것이다:
각 조각이 독립적인 영상 단위로 존재한다
즉, 같은 시간 구간이라도
여러 화질 버전이 존재할 수 있다.
예를 들어:
| 시간 구간 | 1080p | 720p | 480p |
|---|---|---|---|
| 0~2초 | seg1_1080 | seg1_720 | seg1_480 |
| 2~4초 | seg2_1080 | seg2_720 | seg2_480 |
플레이어는 다음과 같은 선택이 가능하다.
- seg1은 1080p로 재생
- seg2는 720p로 전환
즉,
다음 조각부터 화질을 바꿀 수 있다
이것이 ABR의 핵심이다.
2.5 ABR의 동작 원리
플레이어는 단순히 랜덤으로 화질을 바꾸지 않는다.
다음 요소들을 기반으로 판단한다.
1) 다운로드 속도
플레이어는 조각을 다운로드하면서
속도를 측정한다.
예:
- seg1 다운로드: 0.3초 → 빠름
- seg2 다운로드: 1.5초 → 느림
2) 버퍼 상태
- 버퍼가 충분하면 → 고화질 유지
- 버퍼가 줄어들면 → 화질 낮춤
3) 네트워크 변화
속도가 떨어지면:
- 다음 조각부터 낮은 화질 선택
속도가 올라가면:
- 다시 높은 화질로 전환
2.6 ABR의 실제 동작 흐름
플레이어 내부에서는 다음과 같은 흐름이 반복된다.
- 현재 화질로 segment 요청
- 다운로드 시간 측정
- 네트워크 상태 계산
- 다음 segment 화질 결정
이 과정을 통해:
끊김 없이 가능한 최고 화질을 유지하려고 시도한다
3장. HLS 구조와 Playlist(m3u8) 완전 해부
3.1 HLS 구조의 전체 그림
2장에서 HLS는 영상을 “조각 단위로 나눈다”고 설명했다.
하지만 단순히 파일을 나누는 것만으로는 스트리밍이 동작할 수 없다.
플레이어는 다음을 알아야 한다.
- 어떤 화질이 존재하는가
- 어떤 순서로 재생해야 하는가
- 다음에 무엇을 가져와야 하는가
이 문제를 해결하기 위해 HLS는 다음 구조를 가진다.
Playlist + Segment + Player
이 중에서 핵심은:
Playlist (m3u8)
왜냐하면:
플레이어는 실제 영상이 아니라 “playlist를 기준으로” 동작하기 때문이다
3.2 실제 HLS 디렉토리 구조
이론보다 실제 구조를 보는 것이 이해가 빠르다.
📁 예시 구조
hls/
├── master.m3u8
├── 1080p/
│ ├── index.m3u8
│ ├── seg100.ts
│ ├── seg101.ts
│ └── ...
├── 720p/
│ ├── index.m3u8
│ ├── seg100.ts
│ ├── seg101.ts
│ └── ...
└── 480p/
├── index.m3u8
├── seg100.ts
├── seg101.ts
└── ...
✔ 구조 특징
- 화질별로 완전히 분리된 디렉토리
- 동일한 시간 구간이 여러 화질로 존재
예:
1080p/seg100.ts
720p/seg100.ts
480p/seg100.ts
👉 모두 동일한 시간 구간
이 구조 덕분에:
플레이어는 같은 시점에서 화질을 자유롭게 변경할 수 있다 (ABR)
3.3 Master Playlist (전체 스트림 정의)
📄 master.m3u8
#EXTM3U
#EXT-X-STREAM-INF:BANDWIDTH=5000000,RESOLUTION=1920x1080
1080p/index.m3u8
#EXT-X-STREAM-INF:BANDWIDTH=3000000,RESOLUTION=1280x720
720p/index.m3u8
#EXT-X-STREAM-INF:BANDWIDTH=1000000,RESOLUTION=640x360
480p/index.m3u8
✔ 역할
사용 가능한 화질 목록 제공
✔ 주요 정보
- BANDWIDTH → 요구 네트워크 속도
- RESOLUTION → 해상도
✔ 플레이어 동작
- 네트워크 상태 측정
- 적절한 화질 선택
👉 즉:
ABR은 master playlist에서 시작된다
3.4 Media Playlist (실제 재생의 핵심)
📄 index.m3u8
#EXTM3U
#EXT-X-TARGETDURATION:2
#EXT-X-MEDIA-SEQUENCE:100
#EXTINF:2.0,
seg100.ts
#EXTINF:2.0,
seg101.ts
#EXTINF:2.0,
seg102.ts
이 파일은 실제 재생 순서를 정의한다.
3.5 Media Playlist 주요 태그
1) #EXT-X-TARGETDURATION
#EXT-X-TARGETDURATION:2
👉 의미:
segment 최대 길이 (초)
👉 중요성:
- 짧을수록 지연 감소
- 길수록 요청 횟수 감소
👉 핵심:
Latency vs 효율의 트레이드오프
2) #EXT-X-MEDIA-SEQUENCE
#EXT-X-MEDIA-SEQUENCE:100
👉 의미:
현재 playlist의 시작 segment 번호
👉 중요성:
- 라이브 스트리밍 기준 위치
- 현재 재생 시점 판단 기준
3) #EXTINF
#EXTINF:2.0,
seg100.ts
👉 의미:
- segment 길이
- 파일 위치
👉 즉:
“이 조각은 몇 초짜리고, 어디에 있다”
3.6 Segment 파일 형식 (TS vs m4s)
앞에서는 .ts 기준으로 설명했지만,
실제 HLS에서는 두 가지 포맷이 사용된다.
✔ MPEG-TS (.ts)
- 전통적인 HLS 포맷
- 방송용 포맷 기반
- 안정성 높음
👉 특징:
- 구조 단순
- 오류 복구 쉬움
- 호환성 매우 높음
✔ fMP4 (.m4s)
- 최신 HLS에서 사용
- MP4 기반 fragment 구조
👉 특징:
- 압축 효율 좋음
- 파일 크기 작음
- 저지연 스트리밍에 유리
✔ 왜 둘 다 존재하는가
- TS → 안정성과 호환성
- m4s → 효율성과 확장성
👉 핵심 정리:
HLS의 핵심은 포맷이 아니라 “playlist 기반 구조”다
3.7 플레이어 동작 흐름
플레이어는 다음 과정을 반복한다.
전체 흐름
1. master.m3u8 요청
2. 화질 선택
3. index.m3u8 요청
4. segment 다운로드
5. 재생
6. index.m3u8 재요청
👉 핵심 특징:
플레이어는 playlist를 계속 다시 읽는다
3.8 Live Streaming 구조 (Sliding Window)
라이브에서는 playlist가 계속 변경된다.
초기 상태
#EXT-X-MEDIA-SEQUENCE:100
seg100
seg101
seg102
이후
#EXT-X-MEDIA-SEQUENCE:101
seg101
seg102
seg103
✔ 특징
- 오래된 segment 제거
- 새로운 segment 추가
👉 이 구조를:
Sliding Window
라고 한다.
👉 의미:
항상 최신 영상만 유지한다
3.9 HLS 구조의 본질
이제 전체를 정리하면 다음과 같다.
✔ 서버 역할
- playlist 제공
- segment 제공
✔ 플레이어 역할
- playlist 분석
- 다음 segment 계산
- 직접 요청
👉 핵심:
HLS는 서버가 보내는 구조가 아니라
클라이언트가 가져오는 구조다
3.10 구조가 만드는 영향
✔ 장점
- ABR 가능
- CDN 캐싱 가능
- 네트워크 안정성
❗ 단점
- polling 구조 → 지연 발생
- segment 단위 → 즉시성 부족
4장. 왜 HLS는 느릴 수밖에 없는가 (Latency를 구조로 이해하기)
4.1 라이브인데 왜 늦게 보일까
라이브 스트리밍을 보다 보면 이런 상황을 자주 겪는다.
방송자는 이미 어떤 말을 했는데, 시청자는 몇 초 뒤에야 그 장면을 보게 된다.
이걸 단순히 네트워크 문제나 서버 성능 문제로 생각하기 쉽지만,
실제로는 그보다 더 근본적인 이유가 있다.
HLS는 구조적으로 지연이 발생하도록 설계되어 있다.
이 장에서는 그 이유를 “방송자 → 서버 → 시청자” 흐름으로 따라가며 이해한다.
4.2 전체 흐름을 먼저 그려보기
아래 흐름을 한 번 눈으로 보면 전체 구조가 잡힌다.
sequenceDiagram
participant P as 방송자 (Producer)
participant S as 서버 (Origin/CDN)
participant V as 시청자 (Player)
P->>S: 영상 데이터 전송 (실시간)
Note over S: 0~2초 데이터 수집
S-->>S: segment 생성
S-->>S: playlist 업데이트
V->>S: playlist 요청
S-->>V: playlist 응답
V->>S: segment 요청
S-->>V: segment 전달
Note over V: 버퍼링 진행
V-->>V: 재생 시작
이 흐름에서 중요한 건 “누가 언제 기다리는가”다.
4.3 서버는 먼저 기다린다 (Segment 생성)
HLS의 첫 번째 지연은 서버에서 시작된다.
영상은 일정 시간 단위로 잘려서 segment가 된다.
예를 들어 2초 단위라면:
0~2초 → seg1 2~4초 → seg2
여기서 중요한 점은 segment는 실시간으로 쪼개지는 게 아니라,
해당 구간의 영상이 모두 모인 뒤에 생성된다는 것이다.
즉 시간 흐름은 다음과 같다.
0초: 촬영 시작 1초: 아직 seg1 없음 2초: seg1 생성
이 순간 이미 최소 2초의 지연이 발생한다.
4.4 시청자는 바로 알 수 없다 (Playlist 구조)
segment가 만들어졌다고 해서 바로 시청자가 받을 수 있는 것은 아니다.
HLS에서 플레이어는 segment를 직접 알지 못한다.
항상 playlist(m3u8)를 통해서만 정보를 얻는다.
즉 흐름은 이렇게 된다.
segment 생성 → playlist 업데이트 → 플레이어가 다시 요청 → 인지
여기서 중요한 구조적 특징이 나온다.
HLS는 push가 아니라 pull 방식이다.
4.5 시청자는 계속 물어본다 (Polling)
플레이어는 서버에게 계속 이렇게 묻는다.
“새로운 segment 있어?”
이 요청은 일정 주기로 반복된다.
예를 들어 2초마다 요청한다고 가정해보자.
이 경우 timing에 따라 이런 상황이 발생한다.
segment 생성 직후 → 아직 요청 안함 → 모름
2초 후 요청 → 그제야 알게 됨
즉, segment가 준비됐어도 바로 전달되지 않는다.
요청 타이밍에 따라 추가 지연이 발생한다.
4.6 플레이어는 일부러 기다린다 (Buffer)
여기서 가장 큰 지연이 발생한다.
플레이어는 안정적인 재생을 위해 일부 데이터를 미리 쌓는다.
바로 재생하면 끊길 위험이 있기 때문이다.
일반적으로는 다음과 같이 동작한다.
segment 2~3개 확보 → 재생 시작
예를 들어 segment가 2초라면:
2초 × 3개 = 6초
즉 플레이어는 스스로 약 6초 정도를 지연시키고 재생을 시작한다.
이건 문제가 아니라 의도된 동작이다.
끊김을 막기 위해 일부러 늦게 시작한다.
4.7 전체 흐름을 시간으로 다시 보면
이제 전체를 하나로 묶어보자.
촬영 시작
→ 2초 후 segment 생성
→ 1~2초 후 playlist 반영 및 인지
→ 4~6초 버퍼링
→ 재생 시작
결과적으로 약 6~10초의 지연이 발생한다.
이게 우리가 일반적으로 보는 HLS 라이브 지연이다.
4.8 이 구조의 본질
지금까지 내용을 한 문장으로 정리하면 이렇다.
HLS는 “즉시 보여주는 구조”가 아니라
“안정적으로 보여주기 위해 기다리는 구조”다.
이 구조에서는
- 서버도 기다리고
- 시청자도 기다리고
- 플레이어도 기다린다
결국 모든 단계에 “대기”가 들어간다.
4.9 왜 이런 설계를 선택했을까
이건 HLS의 설계 목표와 연결된다.
HLS는 처음부터 초저지연을 목표로 만든 기술이 아니다.
대신 다음을 목표로 했다.
- 끊김 없는 재생
- 글로벌 확장성
- CDN 활용
그래서 선택한 방향은 명확하다.
조금 늦더라도 안정적으로 보여주자
4.10 그래서 생긴 한계
이 구조는 자연스럽게 다음과 같은 결과를 만든다.
장점:
- 끊김이 적다
- 네트워크 변화에 강하다
- 대규모 서비스에 유리하다
단점:
- 실시간성이 떨어진다
- 구조적으로 지연이 발생한다
4.11 핵심 정리
HLS의 지연은 다음 네 가지에서 발생한다.
- segment 생성 대기
- playlist 기반 간접 구조
- polling 방식
- player buffer
이걸 직관적으로 표현하면:
Latency ≈ segment + polling + buffer
그리고 가장 중요한 문장은 이것이다.
HLS는 Low Latency 기술이 아니라
Stable Streaming 기술이다.