포스트

[TIL] MSA 트랜잭션 정합성과 Saga 패턴

MSA 트랜잭션 정합성 문제, 2PC와 Saga 패턴의 동작 방식 및 장단점, 보상 트랜잭션을 활용한 정합성 유지 방법

For the English version of this post, see here.
[TIL] MSA 트랜잭션 정합성과 Saga 패턴

오늘 학습한 개념

  • 2PC

  • Saga 패턴

MSA 환경에서는 하나의 기능이 여러 서비스에 걸쳐 처리될 수 있다.

예를 들면 주문 서비스, 결제 서비스, 재고 서비스가 각각 분리되어 있다면 하나의 주문 요청도 여러 서비스의 데이터 변경을 동반한다.

이때 중요한 문제는 여러 서비스의 데이터 정합성을 어떻게 유지할 것인가이다. 이를 해결하기 위한 대표적인 방식으로 2PC와 Saga 패턴을 학습하였다.


2PC

2PC는 Two-Phase Commit의 약자로, 말 그대로 두 단계로 커밋을 진행하는 분산 트랜잭션 방식이다.

여러 서비스나 데이터베이스가 하나의 트랜잭션에 참여할 때, 모든 참여자가 작업을 수행할 준비가 되었는지 먼저 확인한 뒤 모두 준비되었을 때만 최종 커밋을 수행한다.

  • 동작 방식
    1. 준비 단계
      • 조정자가 각 참여자에게 커밋할 준비가 되었는지 확인한다.

      • 모든 참여자가 가능하다고 응답하면 다음 단계로 넘어간다.

    2. 커밋 단계
      • 모든 참여자가 준비 완료 상태라면 조정자가 커밋을 지시한다.

      • 하나라도 실패하거나 준비되지 않았다면 전체 트랜잭션을 롤백한다.

  • 쉬운 비유
    여러 명이 여행을 가기로 했을 떄, 총무가 모두에게 ‘갈 수 있어?’라고 확인한다.

    이때 모두가 가능하다고 하면 출발하고, 한 명이라도 불가능하다고 하면 여행을 취소하는 방식과 비슷하다.

2PC 장점

  1. 강한 데이터 일관성을 보장할 수 있다
    모든 참여자가 성공해야만 커밋되기 때문에 데이터가 중간 상태로 남을 가능성이 낮다.

  2. 실패 시 전체 롤백이 가능하다
    참여자 중 하나라도 문제가 생기면 전체 작업을 취소할 수 있어 정합성을 맞추기 쉽다.

  3. 트랜잭션 성공 여부가 명확하다
    전체가 성공했는지 실패했는지를 비교적 명확하게 판단할 수 있다.

2PC 단점

  1. 성능 저하가 발생할 수 있다
    모든 참여자의 응답을 기다려야 하므로 처리 속도가 느려질 수 있다.

  2. 장애 전파 가능성이 있다
    참여자 중 하나가 지연되거나 장애가 발생하면 전체 트랜잭션이 영향을 받는다.

  3. MSA 환경과 잘 맞지 않을 수 있다.
    MSA는 서비스 간 독립성과 느슨한 결합을 중요하게 생각하지만, 2PC는 여러 서비스를 하나의 트랜잭션으로 강하게 묶기 때문에 서비스 간 결합도가 높아질 수 있다.

Saga 패턴

Saga 패턴은 하나의 큰 트랜잭션을 여러 개의 작은 로컬 트랜잭션으로 나누어 처리하는 방식이다.

각 서비스는 자신의 작업을 독립적으로 커밋하지만, 중간에 실패가 발생하면 이미 성공한 작업을 되돌리기 위해 보상 트랜잭션을 실행한다.

  • 예시
    주문 처리 흐름이 다음과 같을 때

    1. 주문 생성

    2. 결제 처리

    3. 재고 차감

    4. 배송 요청

    만약 재고 차감 단계에서 실패한다면, 이미 성공한 결제를 취소하고 주문 상태를 취소로 변경하는 보상 작업을 수행한다.

    즉 Saga는 모든 작업을 한 번에 롤백하는 방식이 아니라, 이미 완료된 작업을 보상 작업으로 되돌리는 방식이다.

Saga 장점

  1. MSA 환경에 적합하다
    각 서비스가 자신의 로컬 트랜잭션만 처리하므로 서비스 간 결합도를 낮출 수 있다.

  2. 가용성이 높다
    2PC처럼 모든 서비스가 동시에 준비될 때까지 기다리지 않아도 된다.

    따라서 특정 서비스의 지연이 전체 시스템을 오래 막는 상황을 줄일 수 있다.

  3. 확장성에 유리하다
    서비스들이 독립적으로 동작하기 떄문에 대규모 시스템에서 유연하게 확장하기 좋다.

Saga 단점

  1. 보상 트랜잭션 설계가 어렵다
    실패했을 때 어떤 작업을 되돌려야 하는지 명확하게 설계해야 한다.

  2. 일시적인 데이터 불일치가 발생할 수 있다
    각 단계가 독립적으로 커밋되기 때문에 중간 과정에서는 데이터가 잠시 맞지 않을 수 있다.

  3. 전체 흐름 추적이 복잡하다
    여러 서비스에 걸쳐 이벤트나 요청이 오가기 때문에 장애가 발생했을 때 어느 단계에서 문제가 생겼는지 추적하기 어려울 수 있다.

정리

2PC는 모든 참여자가 성공할 수 있을 때만 커밋하는 방식이므로 강한 일관성을 보장하는 데 유리하지만, 모든 참여자의 응답을 기다려야 하므로 성능과 가용성 측면에서 부담이 있다.

반면 Sage 패턴은 각 서비스를 독립적으로 처리하고 실패 시 보상 트랜잭션을 통해 정합성을 맞추기 때문에 MSA 환경에 더 적합하지만, 보상 로직 설계와 장애 추적이 복잡해질 수 있다.

→ 2PC는 모두가 준비되어야 커밋하는 방식이고, Sage는 각자 처리한 뒤 실패하면 보상 작업으로 정합성을 맞추는 방식이다.


느낀 점

MSA에서는 단순히 트랜잭션을 성공시키는 것뿐만 아니라, 서비스 간 결합도와 장애 상황까지 함께 고려해야 한다는 점을 알게 되었다.

강한 일관성이 필요한 경우에는 2PC가 적합할 수 있지만, 서비스의 독립성과 확장성을 중요하게 생각하는 MSA에서는 Saga 패턴이 더 자주 사용될 수 있을 것 같다.

댓글

궁금한 점, 피드백, 오류 제보를 남겨 주세요.