개발 학습 실습실

이 사이트의 실습은 자바스크립트를 켜야 움직입니다. 아래는 같은 내용을 글로 적은 것입니다.

공부 › 아키텍처와 운영 › 서비스 분리

Saga와 Outbox

서비스마다 DB가 따로일 때 "전부 성공 아니면 전부 취소"를 어떻게 하나

주문, 결제, 재고, 배송이 각자의 DB를 가진 서비스로 나뉘어 있으면 하나의 DB 트랜잭션으로 묶을 수 없습니다. 중간에 실패하면 이미 끝난 단계를 되돌리는 작업을 따로 실행해야 합니다(Saga). 또 DB 저장과 메시지 발행 사이에 서버가 죽으면 둘이 어긋납니다(Outbox가 해결하는 문제).

문서·표준 대조 · microservices.io의 패턴 설명

이 실습에 나오는 개념

분산 트랜잭션과 Saga 패턴
여러 서비스(또는 데이터베이스)에 걸친 작업을 하나의 트랜잭션처럼 처리하는 문제다. 서비스마다 데이터베이스가 따로 있으면 하나의 로컬 트랜잭션으로 묶을 수 없다. 여러 데이터베이스를 묶는 2단계 커밋(2PC)이 있지만 가용성과 결합도 부담이 커 마이크로서비스에서는 잘 쓰지 않는다. Saga 패턴은 각 서비스가 자신의 작업을 차례로 커밋하고, 중간에 실패하면 이미 완료된 작업을 취소하는 보상 작업을 실행해 일관성을 맞추는 방법이다.
보상 트랜잭션
이미 커밋된 작업의 효과를 되돌리기 위해 실행하는 별도의 작업이다. 데이터베이스의 롤백과 달리 반대 동작(예: 결제 취소, 재고 복원)을 수행하는 새로운 트랜잭션이다. Saga 패턴에서 실패 시 이전 단계들을 취소하는 데 쓴다.
Transactional Outbox 패턴
데이터베이스 변경과 메시지 발행을 함께 성공시키기 위한 패턴이다. 메시지를 직접 발행하는 대신, 업무 데이터를 변경하는 것과 같은 트랜잭션에서 보낼 메시지를 별도의 테이블(outbox)에 저장한다. 이후 다른 프로세스가 이 테이블을 읽어 메시지 브로커로 발행한다. DB에는 반영되었는데 메시지가 발행되지 않는 불일치를 막는다.
메시지 전달 보장
메시지가 몇 번 전달되는지에 대한 보장 수준이다. at-most-once는 최대 한 번 전달되어 중복은 없지만 유실될 수 있다. at-least-once는 최소 한 번 전달되어 유실은 없지만 중복될 수 있다. exactly-once는 정확히 한 번 전달된다. 실무에서는 at-least-once로 두고 소비자가 중복을 처리(멱등)하도록 만드는 경우가 많다.
최종 일관성(Eventual Consistency)
데이터를 변경한 직후에는 일부 노드가 이전 값을 보여 줄 수 있지만, 추가 변경이 없으면 시간이 지나 모든 노드가 같은 값을 갖게 된다는 보장이다. 즉시 일관성을 포기하는 대신 가용성과 확장성을 얻는다. 분산 데이터베이스와 마이크로서비스 간 데이터 동기화에서 흔히 채택된다.

이렇게 바꿔 보세요

처음 설정으로 실행하면

  1. 사용자가 주문합니다. 네 서비스가 각자 자기 DB에 작업을 커밋하고, 끝나면 다음 서비스에 이벤트로 알립니다. 전체를 감싸는 하나의 트랜잭션은 없습니다.
  2. 1단계 주문 서비스: 주문 생성 완료. 자기 DB에 커밋하고 다음 단계를 위한 이벤트를 발행합니다.
  3. 2단계 결제 서비스: 결제 승인 완료. 자기 DB에 커밋하고 다음 단계를 위한 이벤트를 발행합니다.
  4. 3단계 재고 서비스: 재고 차감에 실패했습니다. 이 서비스의 로컬 트랜잭션은 롤백되지만, 앞 단계들은 이미 각자의 DB에 커밋된 상태입니다. DB 롤백으로는 되돌릴 수 없습니다.
  5. 보상 1: 결제 서비스가 실패 이벤트를 받아 결제 취소(환불)를 실행합니다. 이미 커밋된 작업을 "취소하는 새 작업"으로 되돌리는 것입니다. 실행한 순서의 반대로 진행합니다.
  6. 보상 2: 주문 서비스가 실패 이벤트를 받아 주문 취소를 실행합니다. 이미 커밋된 작업을 "취소하는 새 작업"으로 되돌리는 것입니다. 실행한 순서의 반대로 진행합니다.
  7. 모든 보상이 끝났습니다. 주문은 취소 상태가 됐고 데이터는 다시 앞뒤가 맞습니다. 다만 보상이 끝나기 전까지는 "결제는 됐는데 주문은 실패"처럼 어긋난 상태가 잠시 존재했습니다.

실행 결과

코드

// 각 단계는 자기 서비스의 로컬 트랜잭션으로 커밋된다
1. 주문 서비스   주문 생성 (PENDING)      보상: 주문 취소
2. 결제 서비스   결제 승인                보상: 결제 취소(환불)
3. 재고 서비스   재고 차감                보상: 재고 복구
4. 배송 서비스   배송 요청                (마지막 단계)

// 단계가 실패하면 "실패" 이벤트를 발행하고,
// 앞선 단계들이 그 이벤트를 받아 자기 보상 작업을 실행한다

이 모형의 전제

Saga는 서비스들이 이벤트를 주고받으며 진행하는 방식(코레오그래피)으로 그렸습니다. 중앙의 조정자가 각 단계를 지시하는 방식(오케스트레이션)도 있으며 보상의 원리는 같습니다. 보상 작업은 항상 성공한다고 단순화했습니다. Outbox 예에서는 서버가 죽는 시점을 가장 문제가 되는 순간으로 고정했습니다. 패턴의 정의는 마이크로서비스 패턴 문헌(microservices.io)의 설명을 따랐습니다.

앞 실습: 서킷 브레이커 · 다음 실습: 게이트웨이와 점진적 전환

이 실습에 나오는 개념

이 실습에서 보는 것

설정

코드


      
    

그림

실행 비교

이렇게 바꿔 보세요