ID3 삽입 시간 delta를 어떻게 측정할까
StreamLive에 ID3 timed metadata를 심어 광고 마커를 테스트하다 보면 결국 시간 문제로 이어집니다. "이 시각에 ID3 tag를 넣으라고 요청했는데, 실제로는 언제 들어갔을까?" 처음엔 단순해 보이는 질문입니다. 요청 시각과 실제 삽입 시각을 빼면 될 것 같지만, 라이브 스트리밍에서는 시간 기준이 여러 개라서 그 차이, 즉 delta를 정의하는 방식부터 정리해야 합니다.
여기서 기준을 대충 잡으면 delta 값이 들쭉날쭉해집니다. 더 위험한 것은, 이렇게 틀린 값을 보고 시스템이 느리다고 오해할 수도 있다는 점입니다.
[ID3 삽입 테스트 대시보드 캡처 첨부 필요]
먼저 시간 기준을 나눠야 한다
테스트에서 확인할 수 있는 시간은 대략 세 가지입니다.
a. adStartTime
이벤트 payload 안에 들어있는 기준 시각
b. API received time
서버가 요청을 받은 시각
c. actual ID3 inserted time
세그먼트 안에서 ID3가 실제 위치한 시각예를 들어 이런 값이 있다고 하겠습니다.
a. adStartTime 2026-05-05 15:36:17.000
b. API received time 2026-05-05 15:36:18.127
c. ID3 inserted time 2026-05-05 15:36:18.553그러면 두 구간을 나눠서 봐야 합니다. b에서 a를 뺀 값은 요청이 기준 시각보다 얼마나 늦게 서버에 도착했는지를 보여주고, c에서 b를 뺀 값은 서버가 요청을 받은 뒤 실제 삽입까지 걸린 시간을 보여줍니다. 이 둘을 더한 c에서 a를 뺀 값이 사용자가 기대한 기준 시각과 실제 삽입 시각의 전체 차이입니다.
b - a = 요청이 기준 시각보다 얼마나 늦게 서버에 도착했는가
c - b = 서버가 요청을 받은 뒤 실제 삽입까지 얼마나 걸렸는가
c - a = 사용자가 기대한 기준 시각과 실제 삽입 시각의 차이이걸 한 덩어리로 보면 원인을 나눌 수 없습니다. 전체 delta는 사실 클라이언트/네트워크/API edge 지연, 서버 스케줄링 지연, 세그먼트와 타임스탬프 정렬 지연이 합쳐진 값이기 때문입니다.
client/network/API edge delay
+ server scheduling delay
+ segment/timestamp alignment delay
= total deltaimmediate는 0ms가 될 수 없다
이름이 "immediate"라서 오해하기 쉽지만, 즉시 삽입은 0ms 삽입을 뜻하지 않습니다. 현실에서는 최소한 아래 구간을 거칩니다.
Client
-> API edge
-> backend
-> live processing pipeline
-> segment muxing
-> HLS output요청이 서버에 도착하기 전까지의 네트워크 지연도 있고, 서버가 받은 뒤 실제 live pipeline에 반영되는 시간도 있습니다. 게다가 HLS는 segment 단위로 움직이기 때문에, immediate 테스트에서 "왜 0ms가 아닌가"라고 묻는 것은 애초에 기준을 잘못 잡은 질문일 수 있습니다.
더 현실적인 질문은 "서버가 요청을 받은 뒤, 첫 ID3 tag가 어느 정도 지연으로 들어가는가"입니다. 즉, immediate에서 핵심으로 봐야 할 값은 앞서 정의한 c - b에 가깝습니다. 물론 사용자 경험 관점에서는 c - a도 중요하지만, 시스템 성능을 볼 때는 b - a와 c - b를 분리해서 봐야 합니다.
fixed_time은 조금 다르다
fixed_time은 특정 시각에 맞춰 삽입하는 방식입니다. 이 경우에는 서버가 미리 계획을 알고 있으므로 immediate보다 안정적으로 시각을 맞출 가능성이 높습니다.
fixed_time:
미리 예약된 시간에 맞춰 삽입
immediate:
요청이 들어온 뒤 가능한 빨리 삽입그래서 fixed_time과 immediate를 같은 기준으로 비교하면 안 됩니다. fixed_time은 예약한 시각과 실제 삽입 시각의 차이를 보는 것이 자연스럽고, immediate는 요청 도착 이후 실제 삽입까지의 처리 시간을 따로 봐야 합니다.
PDT와 PTS는 다르다
HLS manifest에는 EXT-X-PROGRAM-DATE-TIME이 있을 수 있습니다.
#EXT-X-PROGRAM-DATE-TIME:2026-05-05T15:36:16.000+08:00
#EXTINF:4.000,
segment_001.tsPDT는 벽시계 시간입니다. 반면 TS 안의 PTS는 미디어 타임라인이고, 보통 90kHz clock을 씁니다.
PTS tick -> 90000 ticks = 1 second그래서 ID3의 세그먼트 내부 위치는 이렇게 계산합니다.
segment start time = EXT-X-PROGRAM-DATE-TIME
id3 offset = (ID3 PTS - segment first PTS) / 90000
actual ID3 time = segment start time + id3 offset여기서 90000으로 나누는 이유는 MPEG 계열 타임스탬프의 기준 clock이 90kHz이기 때문입니다.
90000 ticks = 1000 ms
90 ticks = 1 msdelta 정의
지금까지 정리한 delta 정의는 다음과 같습니다.
delta_from_target = actual_id3_time - adStartTime
backend_latency = actual_id3_time - api_received_time
request_lag = api_received_time - adStartTime이렇게 나누면 어떤 구간이 문제인지 보입니다. 예를 들어 값이 이렇게 나왔다고 하겠습니다.
request_lag = 1127 ms
backend_latency = 426 ms
delta_from_target = 1553 ms이 경우 전체 delta는 1553ms지만, 서버 처리 자체는 426ms에 불과합니다. 대부분의 지연은 요청이 기준 시각보다 늦게 서버에 들어온 데서 생긴 것입니다. 이 둘을 구분하지 않으면 "백엔드가 1.5초 느리다"고 잘못 판단하게 됩니다.
테스트할 때 남겨야 하는 로그
테스트 자동화를 만들면 최소한 아래 값은 남기는 것이 좋습니다.
| 필드 | 의미 |
|---|---|
| plan_id | 삽입 요청 단위 |
| mode | fixed_time 또는 immediate |
| adStartTime | payload 기준 시각 |
| api_requested_at | 클라이언트 요청 시각 |
| api_received_at | 서버 수신 시각 |
| segment_pdt | 세그먼트 PDT |
| segment_uri | ID3가 발견된 세그먼트 |
| id3_pts | ID3 PES PTS |
| first_pts | 세그먼트 기준 PTS |
| actual_id3_time | 계산된 실제 삽입 시각 |
| delta_ms | 최종 delta |
[ID3 delta 로그 테이블 캡처 첨부 필요]
정리
ID3 삽입 시간은 단순히 "요청 시간 - 발견 시간"으로 보면 안 됩니다. 라이브에서는 벽시계 시간과 미디어 시간이 함께 움직입니다. PDT는 벽시계 기준이고, PTS는 미디어 타임라인입니다. immediate는 0ms를 의미하지 않고, fixed_time은 미리 예약된 처리라 immediate와 비교 기준이 다릅니다.
이 문제의 핵심은 성능보다 기준 정의에 있습니다. 기준을 잘못 잡으면 정상 동작도 장애처럼 보이고, 실제 병목도 엉뚱한 곳으로 몰리게 됩니다.