MSA 트랜잭션 롤백 전략

j·2024년 8월 19일
0

MSA에서 분산 트랜잭션 롤백 전략이 필요한 이유


MSA로 구성하려면 서비스마다의 DB 분리가 필요하다. 그렇게 되면 원자성이 지켜지지 않을 가능성이 있다. 단일 DB인 경우는 단일 ACID DB 트랜잭션 범위 내에서 이 작업이 수행된다.
분산 DB인 경우 각 변경이 다른 DB에서 독립적으로 이루어지기 때문에 중간에 에러가 일어날 경우 데이터의 일관성이 지켜지지 않을 수 있다. 트랜잭션의 경계가 나뉘어짐에 따라 원자성이 지켜지지 않는데 이를 해결하기 위한 전략이 대표적으로 2-Phase-Commit, SAGA 패턴 두가지가 있다.

1. 2-Phase-Commit


분산 트랜잭션을 구현하는데 널리 사용된다. prepare 단계와 commit 단계로 구성된다.

  • Prepare Phase: 관련된 모든 서비스는 commit을 준비하고, transatinon coordinator에 트랜잭션을 시작할 준비가 됐음을 알린다.
  • Commit Phase: 이전 단계에서 트랜잭션을 시작할 준비가 됐다면, coordinator는 commit을 요청한다. 만약에 서비스 하나라도 실패가 발생한다면, coordinator 관련된 모든 서비스에 해당 트랜잭션을 콜백하도록 요청한다.
public interface BankService {
    void prepareTransfer(int amount);
    void commit();
    void rollback();
}

@Component
public class AccountAService implements BankService {
	
    // 계좌 A에서 금액을 차감하기 전의 준비 작업(계좌호출 차감 금액 확인등..)
    @Override
    public void prepareTransfer(int amount) {    
        if(balance >= amount) {
            balance -= amount;
            return true;
        } else {
            return false; // 잔액 부족
        }
    }
}

@Component
public class AccountBService implements BankService {

	// 계좌 B로 입금하기 전의 준비 작업(입금 계좌 확인 및 금액 확인 등..)
    @Override
    public void prepareTransfer(int amount) {
        balance += amount;
        return true;
    }
}

@Service
@RequiredArgsConstructor
public class TransferService {
    
    private final AccountAService accountA;
    private final AccountBService accountB;

    public void transfer(int amount) {
        boolean isPrepared = accountA.prepareTransfer(amount) && accountB.prepareTransfer(amount);

        if (isPrepared) {
            accountA.commit();
            accountB.commit();
        } else {
            accountA.rollback();
            accountB.rollback();
        }
    }
}
  1. Prepare Phase (준비 단계)
  • 유저가 TransferService를 통해서 금액 이체를 요청한다.
  • Coordinator(TransferService)는 계좌A(AccountAService)와 계좌B(AccountBService)에게 prepare 상태인지 확인을 요청한다. (=prepareTransfer 메서드)
  • 각 계좌 서비스는 자신의 상태를 확인해서 prepare 상태면 준비 완료 응답을 반환하고 그렇지 않으면 실패 응답을 반환한다.
  1. Commit/Rollback Phase (커밋/롤백 단계)
  • Coordinator는 모든 계좌 서비스로부터 응답을 받는다.

  • 만약 모든 서비스가 prepared 응답을 반환하면, Coorinator는 각 계좌 서비스에 커밋을 요청한다. (=commit 메서드 호출)

  • commit 호출에 따라 계좌 A에서는 출금이 이루어지고, 계좌 B에서는 입금이 이루어진다.

  • 그러나 하나 이상의 서비스에서 prepared 실패 응답을 받으면, Coordinator는 롤백을 요청한다. (=rollback 메서드 호출)

  • rollback 호출에 따라 이전 상태로 복구된다.


1-2. 2-Phase-Commit 단점


  • 트랜잭션의 책임이 Coordinator node에 있고 이 부분이 단일 실패지점(SPOF)이 될 수 있다.
  • 전체 트랜잭션이 완료될 때까지 서비스에서 사용하는 리소스가 잠겨 있어 서비스가 완료될 때까지 대기해야 한다. 때문에 지연 시간이 늘어나고 리소스가 차단되어 확장이 어려워질 수 있다.
  • NoSQL은 2PC-분산 트랜잭션을 지원하지 않는다.



2. SAGA 패턴


  • SAGA 패턴은 MSA 환경에서 일관성을 지키기 어렵다는 것을 감안하여, 최정 일관성을 더 보장하는 패턴이다. 2PC에서는 트랜잭션을 하나의 트랜잭션으로 묶어서 처리하지만 SAGA 패턴은 긴 트랜잭션을 여러 개의 짧은 로컬 트랜잭션으로 분리하는 접근 방식이다. 각 트랜잭션은 다른 트랜잭션의 완료를 기다리지 않고 독립적으로 실행된다. 만약 중간에 문제가 발생하면 보상 트랜잭션을 진행한다. 보상 트랜잭션이란 서비스에서 트랜잭션 처리를 실패할 경우, 그 서비스의 앞선 다른 서비스에서 처리된 트랜잭션을 되돌리게 하는 트랜잭션이다.

SAGA 패턴은 Choreography-based saga와 Orchestration-based 두가지가 있다.

2-1. Choreography-based SAGA


  • 각 로컬 트랜잭션이 다른 서비스의 로컬 트랜잭션을 이벤트 트리거 하는 방식
  • 중앙집중된 지점이 없이 모든 서비스가 메시지 브로커(RabbitMQ, Kafka)를 통해 이벤트를 Pub/Sub 하는 구조다.
  • 중앙 집중형 관리 방식이 아니어서 SPOF(Single Point Of Failure:단일 실패지점)이 없다.
  • 트랜잭션을 시뮬레이션 하기 위해서 모든 서비스 실행이 필요해서 통합 테스트에 불리하다.
  • 새로운 서비스 추가가 필요할 때 서비스간 연계성 파악이 중요하다. Cyclic Dependency 발생에 주의해야 한다.

  1. 사용자가 요청하면 OrderService는 Order 메서드를 수신하고 Pending 상태의 Order 이벤트를 생성한다.
  2. Order Created 이벤트를 발생시킨다.
  3. CustomerService의 이벤트 핸들러는 요청한 건에 대해 예약 시도한다.
    시도한 결과는 이벤트로 발생시킨다.
  4. OrderService는 Order 이벤트를 승인하거나 거부한다.

2-2. Orchestration-based SAGA

  • Orchestrator가 중앙 집중식 컨트롤러 역할을 하고 각 서비스에 실행할 트랜잭션을 아려주는 방법.
  • Orchestrator는 요청을 실행, 각 서비스의 상태를 확인하고 실패에 대한 복구를 처리한다.
  • 비교적 많은 서비스가 있는 복잡한 워크플로우에 적합하다.
  • Orchestrator가 전체 워크플로우를 관리해서 실패 지점이 될 수 있다.

  1. 사용자가 요청하면 OrderService가 수신하고, Orchestrator는 Create Order를 생성한다.
  2. Orchestrator는 Pending 상태의 Order를 생성한다.
  3. CustormerService에 Reserve Credit 명령을 보낸다.
  4. CustermorService는 Reserve Credit를 시도한다.
  5. 시도한 결과는 메시지 통해 응답한다.
  6. Orchestrator는 최종적으로 Order를 승인하거나 거부한다.

reference


https://velog.io/@ch200203/MSA-%ED%99%98%EA%B2%BD%EC%97%90%EC%84%9C%EC%9D%98-%EB%B6%84%EC%82%B0-%ED%8A%B8%EB%9E%9C%EC%9E%AD%EC%85%98-%EA%B4%80%EB%A6%AC2PC-SAGA-%ED%8C%A8%ED%84%B4

https://waspro.tistory.com/734

https://joobly.tistory.com/69

profile
개발 블로그

0개의 댓글