← Apache Flink 코스

Courses · Day 3

핵심개념 B — 늦게 오는 데이터와 오래 유지되는 상태

스텝 11 / 17

11 / 17
개념 flink-course-11

Checkpointing — Kafka 오프셋과 근본적으로 다른 이유

직관적으로

책을 읽다가 중간에 덮어야 한다면, 그냥 "몇 페이지째였는지"만 적어두는 방법과, 그 페이지까지 읽으며 머릿속에 정리한 등장인물 관계도·줄거리 메모까지 통째로 스냅샷 찍어두는 방법이 있다. Kafka 컨슈머 오프셋은 전자(어디까지 읽었는지)이고, Flink 체크포인트는 후자(그 시점까지의 모든 중간 상태까지)에 가깝다.

실제 사례

study_de의 Kafka 학습 콘텐츠에서 다룬 컨슈머 오프셋은 "파티션의 어느 지점까지 읽었는지"만 기록한다. 반면 Flink 잡 안에서는 keyBy 이후 쌓인 윈도우 집계 중간값, 사용자별 누적 카운트(Keyed State) 등 훨씬 많은 정보가 메모리(또는 RocksDB)에 떠 있다 — 잡이 죽었다가 오프셋만 복원해서 재시작하면, 어디서부터 다시 읽을지는 알아도 그동안 쌓아뒀던 집계값은 전부 날아간다.

정확한 원리

Flink의 체크포인트는 **Chandy-Lamport 알고리즘의 변형(비동기 배리어 스냅샷)**을 쓴다 — 체크포인트 코디네이터가 소스의 오프셋을 기록하고, 스트림에 번호가 매겨진 배리어(barrier)를 주입한다. 이 배리어가 각 연산자를 통과할 때마다, 그 연산자는 "이 배리어보다 앞선 모든 이벤트를 처리한 결과로 만들어진 상태"를 스냅샷으로 저장한다. 즉 체크포인트 n은 "배리어 n 이전의 모든 이벤트는 반영하고, 이후 이벤트는 하나도 반영하지 않은" 상태를 담는다. 장애가 나면 소스를 그 저장된 오프셋으로 되감고, 상태를 마지막 체크포인트에서 복원해 재개한다. 이게 보장하는 건 "상태 변경이 정확히 한 번 반영된다"는 것이지, "모든 이벤트가 물리적으로 정확히 한 번만 처리된다"는 뜻은 아니다 — 진짜 end-to-end exactly-once가 되려면 소스가 되감기(replay) 가능해야 하고 싱크도 멱등적이거나 트랜잭션을 지원해야 한다(study_de의 Kafka Connect Sink 전달보장 학습 콘텐츠에서 다룬 것과 같은 원리).

흔한 오해

"체크포인트를 켜면 모든 이벤트가 무조건 딱 한 번씩만 처리된다"는 오해가 흔하다. 정확히는 **상태 갱신이 정확히 한 번 반영되는 것**을 보장하는 것이고, 실제로 이벤트가 물리적으로 재처리(replay)될 수는 있다 — 다만 그 재처리 결과가 상태에 중복 반영되지 않도록 체크포인트 메커니즘이 막아준다는 게 정확한 이해다. 또한 "체크포인트만 켜면 끝"이라는 오해도 흔한데, 소스가 되감기 불가능하거나(예: 재현 불가능한 큐) 싱크가 멱등적이지 않으면 end-to-end exactly-once는 보장되지 않는다.

확인 문제

Flink 잡이 Kafka에서 읽어 파일 시스템에 결과를 쓰고 있다고 하자. 체크포인트가 켜져 있어도 "파일에 같은 결과가 중복으로 쓰이는" 상황이 발생할 수 있을까? 어떤 조건에서 그럴 수 있는가?