관리 메뉴

공부한것들을 정리하는 블로그 입니다.

최종적 일관성(Eventual Consistency) 본문

경력 실무경험/생각해볼만한 주제

최종적 일관성(Eventual Consistency)

호 두 2025. 9. 29. 14:40
반응형

 

 * 최종적 일관성(Eventual Consistency)

즉각적인 데이터 동기화(Strong Consistency)를 보장하지 않지만, 일정 시간이 지나면 시스템이 일관된 상태로 수렴하는 데이터 일관성 모델입니다. 이는 특히 분산 시스템이나 마이크로서비스 아키텍처에서 데이터 정합성을 유지하는 데 중요한 개념입니다.

 


 1) 즉각적인 데이터 동기화를 보장하지 않음 → 데이터가 모든 서비스에 동일하게 반영되기까지 시간이 걸릴 수 있음
 2) 일정 시간이 지나면 일관된 상태로 수렴 → 메시지 기반 시스템, 이벤트 소싱, 데이터 복제 등의 기술을 활용해 최종적으로 정합성을 유지
 3) 높은 가용성을 보장 → 강한 일관성을 유지하려면 시스템이 대기해야 하지만, 최종적 일관성은 시스템의 독립적인 운영을 가능하게 함


예시 : 

 1) 마이크로서비스 간 데이터 동기화: 주문 서비스(Order Service)와 결제 서비스(Payment Service)가 독립적으로 운영되지만, 최종적으로 결제 상태가 주문에 반영됨
 2) 분산 데이터베이스: 노드 간 데이터 동기화가 이루어지며, 일정 시간이 지나면 데이터 정합성이 맞춰짐
 3) 이벤트 기반 시스템: Kafka, RabbitMQ 등의 메시지 브로커를 활용하여 서비스 간 데이터 일관성을 유지

 


예시2 : 

커머스 도메인에서의 주문과 결제 프로세스: 모노리스 vs 마이크로서비스

 

 1.  커머스 도메인에서 주문과 결제 프로세스를 모노리스 아키텍처로 구축한 경우

   - 모노리스 아키텍처에서는 OrderService가 주문(Order)과 결제(Payment) 애그리게이트를 생성하고, 
   - 결제 대행 서비스(Payment Gateway)를 이용해 결제를 처리한 후, 주문과 결제 애그리게이트의 상태를 변경합니다. 
   - 이후, 결제가 완료되면 배송(Shipping) 애그리게이트를 생성하는 방식으로 동작합니다.
   

   A) 이 모든 과정은 하나의 트랜잭션으로 묶여 처리되며, 데이터베이스의 ACID 특성을 활용해 일관성을 유지합니다.

   - 데이터 일관성을 유지하기 위해 데이터베이스 트랜잭션에 의존
     a) 트랜잭션 롤백 문제: 처리 과정에서 오류가 발생하면, 전체 트랜잭션을 롤백하여 주문 이전 상태로 되돌려야 합니다.
     b) 비즈니스 규칙 추가 시 복잡성 증가: 재고(Stock) 확인 등 다양한 비즈니스 규칙이 추가되면서 프로세스가 복잡해지고, 트랜잭션 수행 시간이 증가하여 성능이 저하됩니다.
     c) 오류 발생 시 원인 분석이 어려움: 트랜잭션이 하나의 애플리케이션 내에서 이루어지므로, 문제가 발생하면 디버깅과 유지보수 비용이 증가합니다.
 

 2. 마이크로서비스 아키텍처에서의 주문과 결제

   - 주문과 결제를 분리 => 서비스 간 협력 방식이 변화
   - 모노리스 아키텍처와 달리 서비스 간 데이터베이스 트랜잭션을 하나로 묶을 수 없기 때문에, 오류 발생 시 데이터 일관성을 유지하는 것이 더 어렵습니다.
 


 3. 트랜잭션과 마이크로서비스의 차이

   - 트랜잭션은 데이터베이스 상태를 변경하는 논리적인 작업 단위로, ACID 특성을 보장하기 위해 잠금(Lock) 제어, 커밋, 롤백을 제공
   - 마이크로서비스 아키텍처에서는 가용성을 중요하게 여기므로 ACID 대신 BASE 접근 방식을 사용
   


 * BASE (Basically Available, Soft State, Eventual Consistency)

마이크로서비스에서는 애그리게이트(집계) 내부에서는 ACID를 유지하지만, 애그리게이트 간에는 최종적 일관성(Eventual Consistency)을 적용합니다.
 1) Basically Available: 항상 가용성을 보장하며, 일부 노드가 장애가 나도 운영 가능
 2) Soft State: 시스템의 상태가 일시적으로 변할 수 있음 (즉각적인 일관성이 아님)
 3) Eventual Consistency: 시간이 지나면 최종적으로 데이터 일관성이 맞춰짐


 4. 이벤트 기반 주문 프로세스

   - 마이크로서비스에서 주문 프로세스는 각 서비스가 독립적으로 동작하면서도, 서로 협력하는 방식으로 구현됩니다.
   ex) 주문(Order)과 결제(Payment) 간의 주문완료/결제진행/발송준비 프로세스
     1) 주문 서비스(Order Service)는 주문을 생성한 후, "대기" 상태로 설정
     2) 결제 서비스(Payment Service)는 잔액을 확인하고 결제 승인 후 상태를 "완료"로 변경
     3) 배송 서비스(Shipping Service)는 결제가 완료된 후 배송 요청을 처리
     4) Kafka 등 메시지 브로커를 활용하여 이벤트를 전달하며 최종적 일관성을 유지
 


 5. 오류 발생 시 이벤트 흐름

   ex) 잔액 부족으로 인해 결제 서비스가 실패했을 때, 주문 애그리게이트의 상태 변화
     1) 주문 서비스(Order Service)는 주문을 생성한 후, "대기" 상태로 설정
     2) 결제 서비스(Payment Service)는 잔액을 확인하고 결제 승인 후 상태를 "실패"로 변경
     3) 사용자가 주문을 조회하면, UI에서 주문 상태를 '결제 대기'로 표시하고, 상세 사유를 '잔액 부족'으로 출력하여 사용자가 다시 결제할 수 있도록 유도합니다.
  

   A) 오류 처리 및 재시도 패턴

   - 외부 결제 대행 서비스에서 일시적인 장애가 발생하더라도, 결제 서비스는 기능의 완전성을 보장해야 합니다. 이를 위해 재시도(Retry) 패턴을 활용할 수 있습니다.
   - 이러한 방식으로 마이크로서비스는 강한 일관성을 유지하는 대신, 최종적 일관성을 보장하면서 가용성을 높이는 방식을 채택합니다.
     1) 1초 대기 후 최대 3회까지 다시 결제를 시도 (+ 지수 백오프 => Rate Limit(요청 제한)이 걸린 상황에서 유용)
     2) 계속 오류 발생 시 "실패 이벤트(Failure Event)"를 발행
     3) 이후 사용자가 다시 결제 요청을 할 수 있도록 안내


  예시3 : 분산 트랜잭션과 사가 패턴

  1. 분산 트랜잭션

   - 분산 트랜잭션은 단일 데이터베이스를 사용하는 모노리스 아키텍처뿐만 아니라 마이크로서비스 아키텍처에서도 활용할 수 있습니다. 
   - 하지만, 가용성과 확장성 측면에서 마이크로서비스의 장점을 제한할 수 있으며, 결국 모노리스와 유사한 구조로 회귀할 가능성이 있습니다.
   

   A) 분산 트랜잭션의 문제점

   - 마이크로서비스에서 각 서비스가 독립적으로 운영될 수 있도록 최적의 데이터 저장소(관계형 데이터베이스, MongoDB, Cassandra 등)를 선택할 수 있지만, 
   - 일부 데이터 저장소는 2PC(2-Phase Commit)와 같은 X/A 프로토콜을 지원하지 않기 때문에 분산 트랜잭션을 사용할 수 없습니다.
   
   - 일부 서비스가 타 서비스의 데이터베이스에 직접 접근하는 구조는 높은 높은 결합도를 초래하고, 서비스 간 응집도를 낮추어 유지보수를 어렵게 만듭니다.
   ex) 주문 서비스 -> 주문DB / 결제DB / 재고DB 에 직접 접근
   
   - 주문 / 결제 / 재고 서비스 모두 자신만의 로직을 갖고 분산 트랜잭션을 지원하는 데이터베이스(DB)를 사용하도록 변경 하여 해결 가능합니다.
   - 하지만, 이렇게 비즈니스 트랜잭션 참여를 API 기반으로 서비스가 협력하는 경우, 각 서비스가 독립적인 트랜잭션을 소유하게 되어 오류 발생 시 전체적인 롤백이 불가능합니다.
   - 결과적으로, 마이크로서비스 아키텍처에서는 데이터 일관성을 유지하기 위해 분산 트랜잭션을 적극적으로 활용하는 것이 어려운 선택이 됩니다. 
   - 대신, 보다 유연하고 확장 가능한 방법이 필요하며, 이를 해결하기 위해 사가(Saga) 패턴이 사용됩니다.
   
   

  2. 사가 패턴

   - 사가(Saga)는, 데이터베이스 잠금을 오랫동안 유지하는 문제를 해결을 위한, 작은 트랜잭션 단위로 분할하여 관리하는 접근법입니다.
   - 사가는 하나의 비즈니스 프로세스를 구성하는 여러 개의 트랜잭션을 포함하며, 개별 트랜잭션 중 하나가 실패하면 이를 보상하는 트랜잭션(Compensating Transaction)을 수행합니다.
   - 즉, 트랜잭션의 롤백을 수행하는 것이 아니라, 이전 상태를 되돌리는 별도의 트랜잭션(보상 트랜잭션)을 실행하는 방식입니다.
   

  3. 사가의 실행 흐름

   (1) 정상 프로세스
     1) 주문 서비스 → (주문 생성) Order 애그리게이트 생성 후 OrderPlaced 이벤트 발행
     2) 재고 서비스 → (재고 감소) 주문된 상품의 재고 차감
     3) 결제 서비스 → (결제 성공) 결제 승인 및 결제 완료 처리
   
   (2) 보상 프로세스 (오류 발생 시)
     1) 결제 서비스 → (결제 실패) 결제 시도 후 결제 대행 서비스의 일시 장애 오류로 PaymentFailed 발생
     2) 주문 서비스 → (주문 삭제) OrderCancelled 이벤트 발행 및 Order 데이터 삭제
     3) 재고 서비스 → (재고 증가) Product의 재고 수량 증가. 차감된 재고를 원상 복구 (보상 트랜잭션 수행)
   
   ** (차이) 중요 개념: 
   - 분산 트랜잭션에서는 각 트랜잭션이 커밋되지 않은 상태에서 롤백이 가능하지만, 
   - 마이크로 서비스 아키텍처에서는 이미 개별 트랜잭션이 커밋되었기 때문에 롤백이 불가능합니다. 
   - 따라서, 이를 해결하기 위해 '롤백'이 아닌 '보상(Compensating)'이라는 개념을 사용합니다.
   

  4. 사가의 구현 방식


   - 사가 패턴은 크게 오케스트레이션(Orchestration) 방식과 코레오그래피(Choreography) 방식으로 구현할 수 있습니다.
   
   (1) 오케스트레이션 (Orchestration) 방식
     - (중앙 집중형) 중앙 서비스에서 트랜잭션 관리
 - 장점 : 흐름이 명확, 관리 용이
 - 단점 : 단일 장애점 발생 가능
   (2) 코레오그래피 (Choreography) 방식
     - (분산형) 각 서비스가 독립적으로 이벤트를 구독
 - 장점 : 확장성이 높고 서비스 간 결합도 낮음
 - 단점 : 이벤트 협력 로직이 복잡해질 수 있음

   5. 결론

   - 마이크로서비스 아키텍처에서는 전통적인 분산 트랜잭션을 활용하는 것이 어렵기 때문에, 사가 패턴을 사용하여 데이터 일관성을 유지해야 합니다.
     1) 분산 트랜잭션은 가용성과 확장성을 제한할 수 있으며, 모노리스 아키텍처로 회귀하는 결과를 초래할 가능성이 있음
     2) 사가 패턴을 활용하면 서비스 간 독립성을 유지하면서도 데이터 정합성을 보장할 수 있음
     3) 오케스트레이션 방식과 코레오그래피 방식 중 비즈니스 요구사항에 따라 적절한 방식을 선택해야 함
   



참고 : 에이콘출판 이벤트 소싱과 마이크로서비스 아키텍처

반응형
Comments