개념
분산 트랜잭션(Distributed Transaction)은 여러개의 독립된 시스템이나 데이터베이스에서 동시에 일어나는 트랜잭션을 일관되게 관리하는 방법입니다.
분산 트랜잭션 역시 단일 트랜잭션과 마찬가지로 ACID(원자성, 일관성, 고립성, 지속성)를 보장해야 합니다.
방법
1. 2PC(Two-Phase Commit)

출처: https://hudi.blog/global-transaction/
2PC(Two-Phase Commit)는 분산 트랜잭션을 처리하기 위한 프로토콜로 준비(Prepare) 단계와 커밋(Commit) 단계로 나누어 트랜잭션을 처리합니다.
- 준비 단계(Prepare Phase): 각 참여 노드는 트랜잭션 준비 상태를 확인하고, 준비 완료를 마스터 노드에 알립니다.
- 커밋 단계(Commit Phase): 마스터 노드는 모든 참여 노드가 준비되었음을 확인하고, 트랜잭션을 커밋하도록 지시합니다. 만약 준비가 완료되지 않은 노드가 있다면 트랜잭션을 롤백합니다.
1.1 단점
우선 성능이 떨어집니다. 준비 단계와 커밋 단계 모두 각 DB의 상태를 알리는 통신이 필요합니다. 그리고 lock이 걸리는 구간이 너무 깁니다. 위 이미지에도 표시되어 있듯이 데이터가 쓰여지는 시점부터 다른 DB들이 Prepare Phase가 완료되는 시점까지 lock에 걸리게 되므로 성능이 저하됩니다.
그리고 MSA에 적용하기 어렵습니다. Monolithic 구조라면 모든 DB에 직접 의존하여 해당 프로토콜을 처리하기 쉽지만, MSA는 각 서비스가 각자 독립된 DB를 사용하기에 다른 서비스의 DB에 직접 의존이 불가능하기 때문입니다.
2. Saga Pattern

출처: https://velog.io/@suhongkim98/MSA%EC%99%80-DDD-Saga-Pattern-6
앞서 살펴본 2PC의 단점들을 보완하기 위해 Saga Pattern이 등장하였습니다. Saga Pattern은 서비스들끼리 이벤트를 주고 받아 특정 서비스에서의 작업이 실패하면 이전까지의 작업이 완료된 마이크서비스들에게 보상 이벤트를 소싱함으로써 보상 트랜잭션을 실행하여 분산 환경에서 원자성(atomicity)을 보장하는 패턴입니다.
💡 이벤트 소싱이란?
이벤트 소싱은 데이터 상태 변화를 이벤트로 기록하고, 해당 이벤트들을 순차적으로 재생하여 현재 상태를 파악하는 방법입니다. 전통적인 데이터 저장 방식과 달리, 이벤트 소싱에서는 데이터 변경 자체가 아닌 변경 이벤트를 저장합니다.
💡 보상 트랜잭션이란?
보상 트랜잭션은 실제로 DB 상에서 물리적으로 트랜잭션을 수행하는게 아니라, 이전의 상태로 다시 업데이트하여 마치 롤백이 된 것처럼 만드는 논리적인 트랜잭션입니다.
Saga Pattern은 크게 Choreographed Saga와 Orchestrated Saga 두 종류로 나뉘어집니다. 하나씩 알아봅시다.
2.1 Choreographed Saga

출처: https://ksh-coding.tistory.com/143
Choreographed Saga는 이벤트 및 보상 트랜잭션 처리 주체가 각 마이크로 서비스인 패턴입니다. 정확히는 이벤트 및 보상 트랜잭션 처리 주체는 각 마이크로 서비스의 메세지 브로커입니다.
자세한 로직은 다음과 같습니다.
- Board 생성 요청이 들어오면 Board 생성 트랜잭션을 실행합니다.
- Message Broker에게 Board 생성 이벤트를 publish합니다.
- Board 생성 이벤트를 subscribe하는 Member 서비스에서 Member 업데이트 트랜잭션을 실행합니다.
- Member 업데이트 트랜잭션의 결과 이벤트를 Message Broker에게 publish합니다.
- Member 업데이트 트랜잭션 성공 시
- 성공 이벤트는 publish는 필수가 아닌 선택 사항입니다.
- 만약 Member 업데이트와 상관없이 Board가 생성되어야 한다면 성공 이벤트를 publish하지 않습니다.
- 만약 Meber가 업데이트 된 후 Board 생성이 되어야 한다면 Board 생성 트랜잭션을 커밋하지 않고 기다리다가 결과 이벤트를 보고 커밋합니다.
- Member 업데이트 트랜잭션 실패 시
- 실패 이벤트는 보상 트랜잭션을 위해 필수적으로 publish합니다.
- Board Service에서 실패 이벤트를 subscribe하여 보상 트랜잭션을 실행합니다.
- 보상 트랜잭션으로 Board 생성 트랜잭션을 롤백합니다.
장점
- 마이크로 서비스 숫자가 적다면 쉽고 간단하게 구현이 가능합니다.
- 기존 MSA 환경에서 추가적인 인프라 리소스가 필요하지 않습니다.
단점
- 마이크로 서비스 숫자가 많으면 복잡성이 증가하고 의존성 순환이 발생할 위험이 있습니다.
- 모니터링 시 현재 이벤트 및 트랜잭션 상태를 추적하기 힘듭니다.
2.2 Orchestrated Saga

출처: https://ksh-coding.tistory.com/143
Orchestrated Saga는 이벤트 및 보상 트랜잭션 처리 주체가 Orchestrator인 패턴입니다. Choreographed Saga는 각 서비스가 직접적으로 이벤트를 주고 받았지만 Orchestrated Saga는 Orchestrator를 통해 이벤트를 주고 받습니다.
자세한 로직은 다음과 같습니다.
- Board 생성 요청이 들어오면 Board 생성 트랜잭션을 실행합니다.
- Orchestrator에게 완료 이벤트를 publish하고 Orchestrator는 subscribe 합니다.
- Orchestrator에서 설정한 이벤트 처리 순서에 따라 Member 업데이트 이벤트를 publish합니다.
- Member Service에서 Member 업데이트 이벤트를 subscribe하여 Member 업데이트 트랜잭션을 실행합니다.
- 결과 이벤트를 Orchestrator에게 publish 합니다.
- Member 업데이트 트랜잭션 성공 시
- 만약 Member 업데이트와 상관 없이 Board가 생성되어야 한다면 결과 이벤트를 publish 하지 않습니다.
- 만약 Member 업데이트 이후 Board가 생성되어야 한다면 Board 생성 트랜잭션을 커밋하지 않고 기다렸다가 결과 이벤트를 보고 커밋합니다.
- Member 업데이트 트랜잭션 실패 시
- Member 업데이트 트랜잭션 실패 이벤트를 Orchestrator에서 subscribe 하여 보상 트랜잭션 이벤트를 Boar Serivce에세 publish 합니다.
- Board Service에서 보상 트랜잭션 이벤트를 subscribe하여 보상 트랜잭션을 실행합니다.
- 보상 트랜잭션으로 Board 생성 트랜잭션을 롤백합니다.
장점
- 각 서비스의 트랜잭션 이벤트를 Orchestrator가 처리하기에 서비스가 추가되더라도 이벤트 구조를 파악하기 쉽고 이벤트 순환 의존이 없습니다.
- 각 서비스는 다른 서비스에 대해 알 필요가 없어지니 결합도가 낮아진다.
- 트랜잭션 이벤트 처리가 모두 Orchestrator에서 이루어지므로 이벤트 및 상태를 추적하기 쉽다.
단점
- Orchestrator 구현을 위한 추가 인프라 리소스가 필요합니다.
- Orchestrator 전체 트랜잭션 이벤트를 처리하므로 단일 장애 지점(SPOF)가 되어 장애 발생 시 다른 서비스로 장애가 전파 될 수 있습니다.
- Orchestrator 구현이 상대적으로 어렵습니다.
참고
https://ksh-coding.tistory.com/143
https://azderica.github.io/01-architecture-msa/