스트림 데이터 수집단계에서 내결함성을 높이기 위한 방법에는 체크포인팅
, 로깅
2가지가 있다.
체크포인팅
이란 시스템의 현재 상태를 저장하는 것을 의미한다. 체크포인트를 활용하여 장애 발생 시 저장된 시점부터 복구가 가능하다.
Flink, Spark Structured Streaming같은 스트림 처리나 DB, 분산시스템에서 많이 사용된다.
체크포인팅를 활용하려면 전역 스냅샷과 데이터 유실 가능성을 염두해 두어야 한다.
전역 스냅샷(Global Snapshot)
은 분산 시스템의 전체 노드 상태를 일관된 시점으로 저장하는 것을 의미한다. 하나의 노드 상태만 저장하면, 다른 노드와의 메시지 교환 상태가 불일치해 복구 시 일관성 오류가 발생할 수 있어서 전역 스냅샷이 필요하다.
체크포인팅 간격이 길면 장애 시 마지막 체크포인트 이후의 데이터가 유실될 수 있다. 간격을 짧게하면 I/O 오버헤드가 증가한다는 단점이 있다.
스트림 데이터는 복잡한 단계와 여러 기술을 사용하기 때문에 스트림 데이터 파이프라인 전체에서 각 단계별로 checkpointing을 구현하는 것은 복잡하다. 비록 Flink, Spark Streaming 같은 처리 엔진은 checkpointing을 지원하지만, 수집 → 버퍼 → 큐 → 처리
로 이어지는 전체 파이프라인의 end-to-end checkpointing은 구현 난이도가 높다.
로깅은 체크포인팅의 복잡성과 비용을 극복하고 장애가 발생하기 전까지 수신된 마지막 메시지까지 복구하는 기능을 제공한다. 로깅은 시스템을 구성하는 각 단계가 수신한 모든 메시지를 자체적으로 저장하고 장애가 발생하면 저장된 메시지를 재처리한다
로깅에는 SBML, RBML, HML 3가지 종류가 있다.
데이터 소스에서 서버로직이 데이터를 받을 때 데이터 유실을 방지할 수 있다.
SBML과 다른 점은 원천 데이터를 저장한다는 것이다.
Kafka를 예로 들어보자면 Receiver(Broker) 측에서 메시지를 안정적이게 저장하는 것을 말한다.
producer가 메시지를 전송할 때 key=user_id
로 partition 지정, replication.factor > 1, acks=all로 설정하여 Broker가 Partition Leader log에 commit하고 Follower replica에도 복제하여 데이터 유실을 방지할 수 있다.
서버로직에서 데이터를 보낼 때 데이터 유실을 방지할 수 있다. RBML과 다른 점은 처리가 완료된 데이터를 저장한다는 것이다.
Kafka producer에서 enable.idempotence=true
설정을 통해 메시지를 중복 없이 전송(retry 시에도 중복 생성 방지)할 수 있지만, SBML(Producer local log) 기능을 위해서는 별도의 local buffer나 durable storage가 필요하다.
RBML과 SBML을 사용하여 데이터 유실을 방지할 수는 있지만 저장해야할 데이터가 2배로 늘어나기 때문에 저장소의 성능이 낮다면 수집 단계에서 부정적인 영향을 미칠 수 있다.
HML
을 복잡도를 줄여 이러한 단점을 극복하고자 했다.
첫번째는 두개의 저장소를 하나로 줄여 전체 과정을 간결화했다. 두번째, 데이터 저장 방식을 비동기로 진행한다.
수집 단계의 유휴 서버를 줄이고 내결함성을 강화하기 위해 중간에 버퍼링 계층을 두는 전략도 있는데 이 내용은 별도 포스팅 예정이다.
참고
실시간 데이터 파이프라인 아키텍처