분산 시스템에서 최종적 일관성이란
-
DB, Cache, 서비스 등 여러 시스템이
특정 시점에는 서로 다른 데이터를 가질 수 있지만
최종적으로는 같은 상태와 값을 갖음을 보장하는 것을 뜻한다.
-
최종적 일관성을 기반으로 구축된 시스템은
노드 간에 엄격한 순서나 동기화된 업데이트를 강제하지 않으므로
제품 재고가 한 서버에서는 몇 초 동안 “재고 있음”으로 표시되고
다른 서버에서는 “재고 없음”으로 표시될 수 있다.
이벤트 기반 시스템에서 강력한 일관성을 유지하는 게 어려운 이유
-
분산 시스템 환경에선
네트워크 지연, 서비스 충돌, 재시도, 파티션 등 예측 불가능한 장애가 가득하다.
-
EDA(Event-Driven Systems) 시스템에서
강력한 일관성을 요구하는 것은
분산 시스템 본질에 대해 도전하는 행위가 된다.
-
예를 들면 사용자가 제품에 대한 리뷰를 제출하면
리뷰 서비스는 “리뷰 생성됨”이라는 이벤트를 생성한다.
이후 분석 서비스는 평균 평점을 업데이트하고
사용자 프로필 서비스는 사용자의 기여 횟수를 기록한다.
한 서비스가 즉시 업데이트되고
다른 서비스가 지연되거나 장애가 발생하면
시스템은 일시적으로 서로 다른 상황을 보여주게 된다.
-
강력한 일관성은 모든 서비스가 성공적으로 완료되거나
아니면 아무것도 완료되지 않아야 한다는 것을 요구하지만
비동기 이벤트 기반 환경에선 충족시키는 건 매우 어렵다.
순서 없는 이벤트를 처리하는 전략
-
순서에 대한 강제성이 없기 때문에
이벤트를 발생한 순서가 아닌
시스템에 이벤트가 도착한 순서대로 작업이 처리되면
의도치 않게 작업 순서가 바뀔 수 있다.
-
이럴 경우 어떻게 대응할 수 있는지 몇 가지 전략에 대해 알아보자.
Event Versioning
-
각 이벤트는 해당 이벤트가 나타내는 상태를 나타내는
버전 또는 시퀀스 번호를 갖게 한다.
-
서비스는 이벤트 처리 시
현재 보유하고 있는 버전과 비교한다.
-
더 최신 버전인 경우 이벤트를 적용하고
이전 버전인 경우 삭제하거나 무시하고
중복된 경우 멱등적으로 처리한다.
-
DynamoDB 및 Couchbase와 같은 시스템은
업데이트 충돌을 안전하게 해결하기 위해
내부 버전 관리(벡터 클록 또는 문서 수정 사용)를 사용하는 경우가 많다.
Idempotent Event Handlers
-
멱등성은 동일한 이벤트를 여러 번 처리해도 동일한 결과가 생성됨을 보장한다.
-
이 원칙은 이벤트가 재시도, 중복 또는 재정렬될 때 시스템을 보호한다.
-
멱등성을 달성하는 방법은
처리된 이벤트 ID를 기록하여 중복을 건너뛴다.
-
업데이트를 가산적인 방식이 아닌
덮어쓰기 방지 방식으로 구성한다.
ex) “발송 카운터 증가” 대신 “주문 상태를 발송됨으로 설정”
Reordering Buffers
-
이벤트가 약간 순서가 어긋나지만
예측할 수 있는 패턴(ex. 순차 번호 매기기)으로 도착하는 경우
서비스는 재정렬 버퍼(Reordering Buffers)를 사용할 수 있다.
-
이 전략은 버퍼 크기와 시간제한을 신중하게 조정해야 한다.
버퍼 크기가 너무 작으면 순서가 어긋난 이벤트가 포함되지 못하고
너무 크면 지연 시간이 불필요하게 증가한다.
Process Step
-
이벤트를 다루는 Small Window를 유지한다.
-
버전 또는 타임스탬프를 기준으로 이벤트를 재정렬한다.
-
순서가 맞춰줬다고 판단이 되면 이벤트를 처리한다.
Example
-
메시징 앱은 수신 채팅 메시지를 즉각적으로 렌더링하기 전에
몇 초 동안 버퍼링하여
“안녕”이 “잘 지내?”보다 먼저 표시되도록 적용할 수 있다.