워터마크는 학습(Training)과 서빙(Serving) 사이의 진정한 경계이다
요약
스트리밍 AI 파이프라인에서 워터마크와 지연 시간의 불일치가 학습과 서빙 간의 데이터 분포 왜곡을 초래함을 경고합니다. 시스템 오류 없이 모델 성능이 조용히 저하되는 문제를 해결하기 위해 워터마크 지연과 재생 일치성을 핵심 지표로 관리해야 합니다.
핵심 포인트
- 워터마크로 인한 데이터 근사치가 학습 데이터와 서빙 데이터 간의 분포 차이를 유발함
- 시스템 장애 없이 모델 성능만 저하되는 '조용한 실패' 모드 주의 필요
- 워터마크 지연과 재생 일치성을 인프라의 일급 평가 지표로 취급해야 함
요약(TL;DR) — 스트리밍 AI 파이프라인은 지연 시간(Latency)과 처리량(Throughput)을 기준으로 평가되지만, 더 깊은 위험은 시간 의미론(Time semantics)에 있습니다. 워터마크(Watermarks), 허용된 지연(Allowed lateness), 그리고 순서가 바뀐 이벤트(Out-of-order events)는 학습(Training)과 서빙(Serving) 사이에서 피처(Feature)의 의미를 조용히 변화시킵니다. 이는 대시보드에서 전혀 포착되지 않는 데이터 분포 왜곡(Distribution skew)을 생성합니다. 왜냐하면 아무것도 고장 난 것처럼 보이지 않기 때문입니다. 파이프라인은 빠르고, 모델은 점수를 매기고 있으며, 수치들은 그저 조용히 틀려 있을 뿐입니다. 해결책은 워터마크 지연(Watermark lag)과 재생 일치성(Replay parity)을 인프라의 각주가 아닌, 일급 평가 지표(First-class evaluation metrics)로 취급하는 것입니다.
스트리밍 AI 인프라에 관한 모든 글은 동일한 수치에 집착합니다: 엔드 투 엔드 지연 시간(End-to-end latency), 초당 이벤트 수(Events per second), p99 조회 시간(p99 lookup time). 이 수치들은 중요합니다. 하지만 실시간 AI 시스템이 실제로 실패하는 지점은 바로 이곳이 아닙니다. 중요한 실패 모드는 훨씬 더 조용하며 대시보드에서 확인하기가 훨씬 어렵습니다. 바로 당신의 Flink 작업과 학습 파이프라인이 "지금(Now)"이 무엇을 의미하는지에 대해 서로 동의하지 않는 순간입니다.
이러한 불일치는 전통적인 의미의 버그가 아닙니다. 아무것도 충돌(Crash)하지 않습니다. 어떤 경고(Alert)도 울리지 않습니다. 시스템은 단지 모델이 학습되었던 것과 더 이상 일치하지 않는 피처 분포(Feature distribution)를 대상으로 점수를 매기기 시작할 뿐이며, 누군가 찾아 나서지 않는 한 프로덕션 환경에서 지속적으로, 영원히 이 작업을 수행합니다.
완벽한 과거로 학습하고 근사적인 현재로 서빙하는 피처
모든 사기 탐지(Fraud) 또는 추천(Recommendation) 모델이 어떤 형태로든 가지고 있는 피처를 생각해 보십시오: "지난 5분간의 트랜잭션", "지난 1시간 동안의 클릭", 또는 "지난 세션 동안 전송된 메시지"와 같은 것입니다. 학습(Training) 시에 이 피처는 완전하고, 정렬되었으며, 이미 확정된 데이터셋을 대상으로 배치(Batch) 방식으로 계산됩니다. 해당 윈도우(Window)에 속하는 모든 이벤트가 그곳에 존재합니다. 조인(Join)은 정확합니다.
서빙(Serving) 단계에서는, 동일한 피처(Feature)가 워터마크(Watermark)에 의해 제한된 상태로 Kafka에서 데이터를 읽어오는 Flink 작업(Job)을 통해 계산됩니다. 워터마크는 특정 시점에 스트림(Stream)이 얼마나 "완전(Complete)"한지에 대한 Flink의 최선의 추측입니다. 이는 명시적이고 의도적인 근사치(Approximation)입니다. 즉, 프레임워크가 윈도우(Window) 결과를 내보내기 위해 뒤처지는 이벤트(Straggling event)를 영원히 기다리지 않도록 하기 위해 선택한 트레이드오프(Tradeoff)입니다.
이것은 동일한 피처에 대한 두 가지 서로 다른 정의입니다. 학습(Training) 단계에서는 실제 카운트(True count)를 보았습니다. 서빙(Serving) 단계에서는 워터마크가 윈도우가 "충분히 완료되었다"고 결정한 시점의 카운트를 봅니다. 일반적인 네트워크 조건에서는 그 격차가 작아 아무도 눈치채지 못합니다. 하지만 모바일 클라이언트의 재시도 폭풍(Retry storm), 파티션 재균형(Partition rebalance), 또는 느린 프로듀서(Slow producer) 상황에서는 그 격차가 벌어지며, 온라인 피처는 모델이 기대하도록 학습된 값에 비해 체계적으로 과소 계산(Undercount)됩니다. 모델이 성능이 저하되는 것이 아닙니다. 동일한 이름 아래 다른 변수가 입력되고 있는 것입니다.
워터마크는 성능 조절 노브(Performance Knob)가 아니라 정확도 조절 노브(Correctness Knob)이다
대부분의 팀은 초기 Flink 설정 시 워터마크 전략(Watermark strategy)과 허용 지연 시간(Allowed lateness)을 한 번 구성하고, 이를 처리량(Throughput)과 메모리 압박(Memory pressure)을 위한 튜닝 파라미터(Tuning parameter)로 취급합니다. 그것은 실수입니다. 워터마크 설정은 허용 가능한 피처 오차(Feature error)에 대한 선언이며, 파이프라인(Pipeline) 담당자뿐만 아니라 모델 품질(Model quality)을 책임지는 사람이 검토해야 합니다.
허용 지연 시간을 엄격하게 설정하면 상태 크기(State size)가 줄어들고 윈도우 방출(Window emission) 속도가 빨라지지만, 정당한 지연 이벤트(Late event)가 피처 계산에서 완전히 누락되는 비율을 조용히 높입니다. 반대로 이를 완화하면 피처의 완전성(Completeness)은 향상되지만, 피처가 서빙 가능해지기까지의 지연(Delay)이 증가하며, 이는 지연 시간(Latency)에 민감한 추론(Inference) 경로에서는 전혀 허용되지 않을 수도 있습니다. 단순히 "정답"인 설정은 없습니다. 오직 모델이 가정하도록 학습된 설정과 그렇지 않은 설정만이 존재할 뿐입니다.
불편한 점은 백프레셔 (backpressure), 체크포인트 실패 (checkpoint failures), 컨슈머 지연 (consumer lag)이 없는, 겉보기에 매우 건강해 보이는 스트리밍 시스템을 운영하면서도, 워터마크 (watermark) 정책이 학습 가정 (training assumption)으로부터 조용히 벗어나고 있을 수 있다는 것입니다. 인프라의 건강함 (Infra health)과 피처의 정확성 (feature correctness)은 동일한 신호가 아니며, 대부분의 관측성 스택 (observability stacks)은 오직 전자의 신호만을 감시합니다.
지연된 데이터는 사라지지 않고, 단지 모델의 믿음을 재정렬할 뿐이다
순서가 어긋난 이벤트 (Out-of-order events)는 문제를 심화시킵니다. "순차적인 마지막 N개의 이벤트"를 조건으로 하는 모델은, 파이프라인이 집계 (aggregation) 전에 이벤트 시간 (event-time) 기준으로 명시적으로 재정렬하지 않는 한, 단순히 이벤트 시간 순서가 아니라 도착 순서에 따라 다른 결과값을 얻게 됩니다. Flink가 이를 수행할 수는 있지만, 이는 버퍼링 (buffering) 비용을 발생시키며, 버퍼링은 지연 시간 (latency)을 초래합니다. 실시간 서빙 (real-time serving)에서의 지연 시간 예산 (latency budgets)은 보통 시스템에서 가장 엄격한 제약 조건입니다. 따라서 팀들은 파이프라인이 여전히 "작동"하기 때문에, 이러한 트레이드오프 (tradeoff)를 어디에도 기록하지 않은 채 정확성을 속도와 맞바꿉니다.
두 번째로 더 교묘한 버전은 체크포인트 복구 (checkpoint recovery)입니다. Flink 작업이 실패 후 재시작되어 Kafka로부터 이벤트를 다시 재생 (replay)할 때, 최소 한 번 (at-least-once) 의미론 (semantics)은 이미 상태 저장 집계 (stateful aggregation)에 기여한 이벤트를 다시 처리할 수 있습니다. 만약 집계 로직이 재생 시 멱등성 (idempotent)을 보장하지 않는다면, 피처 스토어 (feature store)에는 이미 방출되어 실시간 요청의 점수를 매기는 데 사용된 윈도우 (windows) 내에 중복된 카운트가 포함되게 됩니다. 아무도 이를 데이터 품질 사고로 보지 않는데, 왜냐하면 사고처럼 보이지 않고 그저 화요일에 사기 점수 (fraud score)가 약간 높게 나온 것처럼 보이기 때문입니다.
처리량(Throughput)이 아닌 시간(Time)을 중심으로 설계하기
해결책은 다른 프레임워크를 사용하는 것이 아닙니다. 다른 설계 질문을 던지는 것입니다. "Kafka와 Flink가 모델에 피처를 얼마나 빨리 전달할 수 있는가"를 묻는 대신, "현실적인 지연 (lateness) 및 재생 (replay) 조건 하에서 스트리밍 파이프라인의 피처 정의가 배치 (batch) 파이프라인의 정의와 일치하는가"를 물어야 합니다. 이는 여러 아키텍처 결정 사항을 재구성합니다:
-
추론(Inference)이 얼마나 빠르게 일어나는가보다 어디에서 일어나는가가 더 중요합니다. Flink 연산자(operator) 내부에서 해당 워터마크(watermark) 시점의 상태(state)를 사용하여 인라인(inline)으로 점수(scoring)를 매기는 것은, 피처(feature)를 외부 피처 스토어(feature store)로 방출하고 별도의 모델 서버가 나중에 이를 가져오게 하는 것과는 다른 시간적 의미론(time semantic)을 갖습니다. 이러한 추가적인 홉(hop)은 워터마크의 신선도(staleness)에 더해 자체적인 신선도 저하를 유발합니다.
-
모델에 입력되는 모든 상태 기반 집계(stateful aggregation)에 대해, 재실행(replay) 시의 멱등성(Idempotency)은 가정되는 것이 아니라 반드시 검증되어야 합니다. 만약 체크포인트(checkpoint)로부터 작업을 재시작했을 때 이미 점수가 매겨진 이벤트의 피처 값이 변경될 수 있다면, 이는 예외적인 상황(edge case)이 아니라 실시간 정확성 버그(live correctness bug)입니다.
Fe
AI 자동 생성 콘텐츠
본 콘텐츠는 Dev.to AI tag의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기