개발자는 기록이 답이다
[이론] 최종적 일관성이란 무엇인가? 본문
최종적 일관성(Eventual Consistency)은 즉각적인 데이터 동기화(Strong Consistency)를 보장하지 않지만, 일정 시간이 지나면 시스템이 일관된 상태로 수렴하는 데이터 일관성 모델입니다. 이는 특히 분산 시스템이나 마이크로서비스 아키텍처에서 데이터 정합성을 유지하는 데 중요한 개념입니다.
✅ 특징
- 즉각적인 데이터 동기화를 보장하지 않음 → 데이터가 모든 서비스에 동일하게 반영되기까지 시간이 걸릴 수 있음
- 일정 시간이 지나면 일관된 상태로 수렴 → 메시지 기반 시스템, 이벤트 소싱, 데이터 복제 등의 기술을 활용해 최종적으로 정합성을 유지
- 높은 가용성을 보장 → 강한 일관성을 유지하려면 시스템이 대기해야 하지만, 최종적 일관성은 시스템의 독립적인 운영을 가능하게 함
✅ 사용 사례
- 마이크로서비스 간 데이터 동기화: 주문 서비스(Order Service)와 결제 서비스(Payment Service)가 독립적으로 운영되지만, 최종적으로 결제 상태가 주문에 반영됨
- 분산 데이터베이스: 노드 간 데이터 동기화가 이루어지며, 일정 시간이 지나면 데이터 정합성이 맞춰짐
- 이벤트 기반 시스템: Kafka, RabbitMQ 등의 메시지 브로커를 활용하여 서비스 간 데이터 일관성을 유지
커머스 도메인에서의 주문과 결제 프로세스: 모노리스 vs 마이크로서비스
커머스 도메인에서 주문과 결제 프로세스를 모노리스 아키텍처로 구축한 경우를 살펴보겠습니다.
모노리스 아키텍처에서는 OrderService가 주문(Order)과 결제(Payment) 애그리게이트를 생성하고, 결제 대행 서비스(Payment Gateway)를 이용해 결제를 처리한 후 주문과 결제 애그리게이트의 상태를 변경합니다. 이후, 결제가 완료되면 배송(Shipping) 애그리게이트를 생성하는 방식으로 동작합니다.

1. 모노리스 아키텍처의 특징과 문제점
모노리스 아키텍처는 데이터 일관성을 유지하기 위해 데이터베이스 트랜잭션에 의존합니다. 단순한 구조에서는 이러한 방식이 효과적일 수 있지만, 다음과 같은 문제가 발생할 수 있습니다.
- 트랜잭션 롤백 문제: 처리 과정에서 오류가 발생하면, 전체 트랜잭션을 롤백하여 주문 이전 상태로 되돌려야 합니다.
- 비즈니스 규칙 추가 시 복잡성 증가: 재고 확인 등 다양한 비즈니스 규칙이 추가되면서 프로세스가 복잡해지고, 트랜잭션 수행 시간이 증가하여 성능이 저하됩니다.
- 오류 발생 시 원인 분석이 어려움: 트랜잭션이 하나의 애플리케이션 내에서 이루어지므로, 문제가 발생하면 디버깅과 유지보수 비용이 증가합니다.
이러한 한계를 해결하기 위해 마이크로서비스 아키텍처가 도입될 수 있습니다.
2. 마이크로서비스 아키텍처에서의 주문과 결제
마이크로서비스 아키텍처에서는 주문과 결제를 분리하면서, 서비스 간 협력 방식이 변화합니다.
- 단순히 RESTful API 호출을 통해 서비스 간 통신하는 방식을 사용할 수도 있지만, TCP/IP는 신뢰할 수 있는 통신 방식이 아니므로 재시도(Retry), 서킷 브레이커(Circuit Breaker) 같은 보완 패턴이 필요합니다.
- 특히, 모노리스 아키텍처와 달리 서비스 간 데이터베이스 트랜잭션을 하나로 묶을 수 없기 때문에, 오류 발생 시 데이터 일관성을 유지하는 것이 더 어렵습니다.
📌 TCP/IP에서 통신 오류는 극히 드물게 발생하지만, 100% 신뢰할 수 있는 프로토콜은 아닙니다. TCP/IP는 Best Effort(최선을 다해 전송)을 목표로 설계되었으며, 전송 실패 가능성이 존재합니다. 따라서 마이크로서비스에서는 이를 보완하는 패턴이 필요합니다.
3. 트랜잭션과 마이크로서비스의 차이
트랜잭션은 데이터베이스 상태를 변경하는 논리적인 작업 단위로, ACID 특성을 보장하기 위해 잠금(Lock) 제어, 커밋, 롤백을 제공합니다.
하지만, 마이크로서비스 아키텍처에서는 가용성을 중요하게 여기므로 ACID 대신 BASE 접근 방식을 사용합니다.
BASE (Basically Available, Soft State, Eventual Consistency)란?

- Basically Available: 항상 가용성을 보장하며, 일부 노드가 장애가 나도 운영 가능
- Soft State: 시스템의 상태가 일시적으로 변할 수 있음 (즉각적인 일관성이 아님)
- Eventual Consistency: 시간이 지나면 최종적으로 데이터 일관성이 맞춰짐
마이크로서비스에서는 애그리게이트(집계) 내부에서는 ACID를 유지하지만, 애그리게이트 간에는 최종적 일관성(Eventual Consistency)을 적용합니다.
4. 이벤트 기반 주문 프로세스
마이크로서비스에서 주문 프로세스는 각 서비스가 독립적으로 동작하면서도, 서로 협력하는 방식으로 구현됩니다.


- 주문 서비스(Order Service)는 주문을 생성한 후, "대기" 상태로 설정
- 결제 서비스(Payment Service)는 잔액을 확인하고 결제 승인 후 상태를 "완료"로 변경
- 배송 서비스(Shipping Service)는 결제가 완료된 후 배송 요청을 처리
- Kafka 등 메시지 브로커를 활용하여 이벤트를 전달하며 최종적 일관성을 유지
📌 이벤트 기반 시스템을 사용 시 이점
✅ 요청-응답 간 대기 시간을 줄일 수 있음
✅ 데이터베이스 잠금을 최소화하여 더 많은 요청을 처리 가능
✅ 각 서비스가 독립적으로 운영되며 장애 발생 시 영향 최소화
5. 오류 발생 시 이벤트 흐름

- 위 그림에서는 잔액 부족으로 인해 결제 서비스가 실패했을 때, 주문 애그리게이트의 상태 변화를 보여줍니다.
- 사용자가 주문을 조회하면, UI에서 주문 상태를 '결제 대기'로 표시하고, 상세 사유를 '잔액 부족'으로 출력하여 사용자가 다시 결제할 수 있도록 유도합니다.
오류 처리 및 재시도 패턴
외부 결제 대행 서비스에서 일시적인 장애가 발생하더라도, 결제 서비스는 기능의 완전성을 보장해야 합니다. 이를 위해 재시도(Retry) 패턴을 활용할 수 있습니다.
- 1초 대기 후 최대 3회까지 다시 결제를 시도
- 계속 오류 발생 시 "실패 이벤트(Failure Event)"를 발행
- 이후 사용자가 다시 결제 요청을 할 수 있도록 안내
이러한 방식으로 마이크로서비스는 강한 일관성을 유지하는 대신, 최종적 일관성을 보장하면서 가용성을 높이는 방식을 채택합니다.
기업 통합 패턴 (Enterprise Integration Patterns)
마이크로서비스 아키텍처에서 최종적 일관성(Eventual Consistency)은 서로 협력하는 시스템 간의 상호작용을 통해 유지됩니다. 그레고르 호페와 바비 울프는 기업 통합 패턴(Enterprise Integration Patterns, EIP)에서 다양한 시스템 간 협력 패턴을 소개했으며, 이 중 라우팅 슬립(Routing Slip)과 프로세스 매니저(Process Manager) 패턴을 살펴보겠습니다.
1. 라우팅 슬립 패턴 (Routing Slip Pattern)
라우팅 슬립 패턴은 미리 정의된 규칙에 따라 메시지를 하나 이상의 대상에게 전달하는 방식입니다. 복잡한 비즈니스 프로세스를 수행할 때, 여러 개의 프로세스를 통과하면서 규칙을 적용하는 것이 가능합니다.
📌 예제: 메시지가 도착하면 시작 프로시저(A)가 메시지를 검사한 후 직접 처리하거나 다음 프로시저(B, C)로 전달하는 방식으로 동작합니다.

✅ 특징
- 단일 구성 요소(프로시저)뿐만 아니라 일련의 구성 요소를 통과하면서 비즈니스 규칙을 충족하는지 검사
- 파이프-필터(Pipe-Filter) 아키텍처와 유사, 각 필터는 메시지를 검사하고 비즈니스 규칙을 적용한 후 다음 필터로 전달
- 외부 시스템과의 통신 결과에 따라 프로세스 경로가 변경될 수 있음
✅ 사용 사례
- 주문 처리 시스템에서, 주문을 받은 후 결제 승인 → 재고 확인 → 배송 요청 과정을 자동화할 때 사용 가능
- 서비스 간 메시지를 특정 비즈니스 로직에 따라 동적으로 라우팅할 때 활용 가능
2. 프로세스 매니저 패턴 (Process Manager Pattern)
라우팅 슬립 패턴은 메시지를 동적으로 라우팅할 수 있지만, 두 가지 제약 사항이 있습니다.
- 처리 순서는 미리 정의되어 있어야 한다.
- 처리 순서는 선형적으로만 진행되어야 한다.
하지만 실제 비즈니스 로직에서는 처리 순서가 동적으로 결정될 수도 있고, 병렬 실행이 필요할 수도 있습니다. 이때 프로세스 매니저 패턴을 사용하면 실행 흐름을 보다 유연하게 조정할 수 있습니다.
📌 예제: 결제 승인 후 재고 부족이 감지되었을 경우 자동으로 재입고 요청을 생성하거나 대체 상품을 추천하는 동적 프로세스를 운영할 수 있습니다.

✅ 특징
- 라우팅 슬립이 고정된 순서로 메시지를 전달하는 반면, 프로세스 매니저는 실행 결과에 따라 다음 프로세스를 동적으로 결정
- 여러 개의 프로세스를 병렬로 실행할 수도 있음
- 대부분의 워크플로우 엔진(Business Process Management, BPM)이 이 패턴을 사용
✅ 사용 사례
- 결제 서비스에서, 신용카드 결제가 실패하면 즉시 다른 결제 수단(예: 계좌이체, 포인트 결제)으로 전환하는 프로세스
- 고객 지원 요청 처리에서, 상담원이 배정되지 않으면 자동으로 다른 부서로 티켓을 전달하는 기능
분산 트랜잭션과 사가 패턴
1. 분산 트랜잭션
분산 트랜잭션은 단일 데이터베이스를 사용하는 모노리스 아키텍처뿐만 아니라 마이크로서비스 아키텍처에서도 활용할 수 있습니다. 하지만, 가용성과 확장성 측면에서 마이크로서비스의 장점을 제한할 수 있으며, 결국 모노리스와 유사한 구조로 회귀할 가능성이 있습니다.
분산 트랜잭션의 문제점
- 마이크로서비스에서 각 서비스가 독립적으로 운영될 수 있도록 최적의 데이터 저장소(관계형 데이터베이스, MongoDB, Cassandra 등)를 선택할 수 있지만, 일부 데이터 저장소는 2PC(2-Phase Commit)와 같은 X/A 프로토콜을 지원하지 않기 때문에 분산 트랜잭션을 사용할 수 없습니다.
- X/A 프로토콜 : X/A 프로토콜은 트랜잭션 관리자(Transaction Manager)가 여러 분산 데이터 소스를 하나의 글로벌 트랜잭션으로 관리하는 표준 프로토콜입니다. 가장 대표적인 기법은 2PC(2-Phase Commit, 2단계 커밋)으로, 트랜잭션을 원자적으로 처리하는 것을 보장합니다.
- ✅ X/A 프로토콜을 지원하는 데이터베이스 및 메시지 브로커
- 관계형 데이터베이스(RDBMS): Oracle, Microsoft SQL Server, PostgreSQL(MySQL은 기본적으로 미지원)
- 메시지 브로커: IBM MQ, ActiveMQ, TIBCO EMS
- ❌ X/A 프로토콜을 지원하지 않는 데이터 저장소
- NoSQL 데이터베이스: MongoDB, Cassandra, DynamoDB 등
- 대부분의 클라우드 기반 메시지 브로커: Kafka, RabbitMQ
- ✅ X/A 프로토콜을 지원하는 데이터베이스 및 메시지 브로커
- X/A 프로토콜 : X/A 프로토콜은 트랜잭션 관리자(Transaction Manager)가 여러 분산 데이터 소스를 하나의 글로벌 트랜잭션으로 관리하는 표준 프로토콜입니다. 가장 대표적인 기법은 2PC(2-Phase Commit, 2단계 커밋)으로, 트랜잭션을 원자적으로 처리하는 것을 보장합니다.

- 6-8 그림을 살펴보면, 주문 서비스가 결제 및 재고 서비스의 데이터베이스에 직접 접근하는 구조는 높은 결합도를 초래하고, 서비스 간 응집도를 낮추어 유지보수를 어렵게 만듭니다.

- 6-9 그림을 살펴보면, 주문, 결제 재고 서비스 모두 자신만의 로직을 갖고 분산 트랜잭션을 지우너하는 데이터베이스를 사용합니다. 하지만 비즈니스 트랜잭션 참여를 API 기반으로 서비스가 협력하는 경우, 각 서비스가 독립적인 트랜잭션을 소유하게 되어 오류 발생 시 전체적인 롤백이 불가능합니다.
결과적으로, 마이크로서비스 아키텍처에서는 데이터 일관성을 유지하기 위해 분산 트랜잭션을 적극적으로 활용하는 것이 어려운 선택이 됩니다. 대신, 보다 유연하고 확장 가능한 방법이 필요하며, 이를 해결하기 위해 사가(Saga) 패턴이 사용됩니다.
2. 사가 패턴
사가(Saga)는 장기 실행 트랜잭션(Long-running transaction)에서 데이터베이스 잠금을 오랫동안 유지하는 문제를 해결하기 위해 작은 트랜잭션 단위로 분할하여 관리하는 접근법입니다. 마이크로서비스 아키텍처에서는 사가 패턴을 활용하여 비즈니스 프로세스에서 발생하는 여러 서비스 간의 데이터 일관성을 유지할 수 있습니다.
사가의 개념
사가(Saga)의 사전적 의미는 '일련의 사건'으로, 마이크로서비스에서는 비즈니스 프로세스를 구성하는 개별 트랜잭션들의 흐름을 의미합니다.
- 사가는 하나의 비즈니스 프로세스를 구성하는 여러 개의 트랜잭션을 포함하며, 개별 트랜잭션 중 하나가 실패하면 이를 보상하는 트랜잭션(Compensating Transaction)을 수행합니다.
- 즉, 트랜잭션의 롤백을 수행하는 것이 아니라, 이전 상태를 되돌리는 별도의 트랜잭션(보상 트랜잭션)을 실행하는 방식입니다.
3. 사가의 실행 흐름
(1) 정상 프로세스

- 주문 서비스 → Order 애그리게이트 생성 후 OrderPlaced 이벤트 발행
- 재고 서비스 → 주문된 상품의 재고 차감
- 결제 서비스 → 결제 승인 및 결제 완료 처리
(2) 보상 프로세스 (오류 발생 시)

- 결제 서비스→ 결제 시도 후 결제 대행 서비스의 일시 장애 오류로 PaymentFailed 발생
- 주문 서비스 → OrderCancelled 이벤트 발행 및 Order 데이터 삭제
- 재고 서비스 → Product의 재고 수량 증가. 차감된 재고를 원상 복구 (보상 트랜잭션 수행)
📌 중요 개념: 분산 트랜잭션에서는 각 트랜잭션이 커밋되지 않은 상태에서 롤백이 가능하지만, 마이크로 서비스 아키텍처에서는 이미 개별 트랜잭션이 커밋되었기 때문에 롤백이 불가능합니다. 따라서, 이를 해결하기 위해 '롤백'이 아닌 '보상(Compensating)'이라는 개념을 사용합니다.
4. 사가의 구현 방식
사가 패턴은 크게 오케스트레이션(Orchestration) 방식과 코레오그래피(Choreography) 방식으로 구현할 수 있습니다.
- 오케스트레이션과 코레오그래피의 상세한 차이는 microservices.io에서 확인할 수 있습니다.
(1) 오케스트레이션 (Orchestration) 방식 - 중앙 집중형
- 중앙에서 트랜잭션의 흐름을 관리하는 중앙 집중형 방식
- 하나의 서비스(사가 오케스트레이터)가 트랜잭션을 순차적으로 실행하고, 이벤트를 조정하여 일관성을 유지
- 중앙 서비스가 트랜잭션을 제어하므로 비즈니스 로직을 명확하게 관리할 수 있지만, 중앙 집중형 구조로 인해 단일 장애점(Single Point of Failure, SPOF)이 될 수도 있음
📌 사용 사례: 예약 시스템, 결제 시스템 등 트랜잭션의 순서가 중요하고 중앙에서 제어가 필요한 경우
(2) 코레오그래피 (Choreography) 방식 - 분산형
- 각 서비스가 자율적으로 도메인 이벤트를 구독하고 반응하는 방식
- 중앙 서비스 없이 각 서비스가 독립적으로 동작하며, 이벤트 기반으로 트랜잭션을 수행
- 확장성이 뛰어나고 서비스 간 결합도가 낮아지는 장점이 있지만, 서비스 간의 복잡한 협력을 관리해야 하는 부담이 있음
📌 사용 사례: 분산 환경에서의 데이터 동기화, 동적으로 변하는 비즈니스 프로세스
✅ 두 가지 방식 비교
방식 | 특징 | 장점 | 단점 |
오케스트레이션 | 중앙 서비스에서 트랜잭션 관리 | 흐름이 명확, 관리 용이 | 단일 장애점 발생 가능 |
코레오그래피 | 각 서비스가 독립적으로 이벤트를 구독 | 확장성이 높고 서비스 간 결합도 낮음 | 이벤트 협력 로직이 복잡해질 수 있음 |
5. 결론
마이크로서비스 아키텍처에서는 전통적인 분산 트랜잭션을 활용하는 것이 어렵기 때문에, 사가 패턴을 사용하여 데이터 일관성을 유지해야 합니다.
- 분산 트랜잭션은 가용성과 확장성을 제한할 수 있으며, 모노리스 아키텍처로 회귀하는 결과를 초래할 가능성이 있음
- 사가 패턴을 활용하면 서비스 간 독립성을 유지하면서도 데이터 정합성을 보장할 수 있음
- 오케스트레이션 방식과 코레오그래피 방식 중 비즈니스 요구사항에 따라 적절한 방식을 선택해야 함
📌 참고 자료