Chap3. 데이터 일관성 및 복구 전략

데이터 일관성을 위협하는 요소들

단일 데이터베이스를 사용하는 모놀리식 환경에서는 DB 트랜잭션(Transaction) 하나로 모든 정합성을 보장할 수 있었습니다. 하지만 서비스가 쪼개지고 DB가 분리된 분산 환경에서는 상황이 달라집니다.

1. 메시지 유실 (Message Loss)

  • 상황:

    • 주문 서비스에서 주문을 생성하고, 재고 서비스로 재고 감소 요청을 보냈는데, 네트워크 오류 등으로 요청 자체가 사라진 경우입니다.

  • 결과:

    • 주문은 생성되었으나 재고는 그대로인 상태가 되어 데이터 불일치가 발생합니다.

2. 메시지 중복 (Message Duplication)

  • 상황:

    • 메시지 유실을 막기 위해 재시도같은 메커니즘을 활용했을 때, 메시지 중복이 발생하여 일관성이 깨지는 경우입니다. (이 외에도 일관성을 깨뜨리는 요소는 다양하게 존재합니다.)

    • 첫 번째 요청이 성공했음에도 불구하고 Timeout과 같은 이유 등으로 응답을 받지 못해서 같은 요청을 한 번 더 보낸 경우입니다.

  • 결과:

    • 재고가 두 번 차감되는 등 데이터 정합성이 맞지 않게됩니다.

  • 해결책:

    • 멱등성을 보장하는 설계가 필요합니다.

3. 순서 보장 실패 (Out of Order)

  • 상황:

    • 상품 생성 → 상품 수정 순으로 요청을 보냈는데, 네트워크 지연 등으로 인해 ‘상품 수정’ 요청이 먼저 도착해 버린 경우

  • 결과:

    • 없는 상품을 수정하려고 하거나, 최종 데이터 상태가 엉망이 될 수 있습니다.

    • Kafka의 순서 보장 이슈 문제가 존재합니다.

4. 동시성 문제

  • 상황:

    • 애플리케이션에서 멀티 스레드 문제가 아니라, 외부 저장소(DB, Redis 등)를 공유할 때 발생하는 문제입니다.

    • 동시성 문제 또한 데이터 일관성을 깨뜨리곤 합니다.

  • 예시:

    • 재고가 1개 남았는데, 두 개의 주문 요청이 동시에 DB를 조회해서 ‘재고 있음’을 확인하고 각각 주문을 성공시켜 버리는(갱실 손실 등)입니다.

분산 환경에서 트랜잭션을 보장하려면?

분산 환경에서의 메시지 유실 = 분산 환경의 복잡성 + 트랜잭션 관리 실패

합리적인 수준의 복잡도를 가진 분산 환경이라면 그 안에서 중요해지는 것은 트랜잭션을 어떻게 관리할 것인가 입니다.

결국 핵심은 ‘나눠진 여러 DB 간의 트랜잭션을 어떻게 하나로 묶을 것인가’입니다. 단일 DB에서 쉽게 보장했던 원자성을 분산 환경에서도 적절하게 구현해야 합니다.

이를 위해 다음과 같은 디자인 패턴들이 존재합니다.

1. 트랜잭셔널 아웃박스 패턴 (Transactional Outbox Pattern)

  • 목적:

    • 비즈니스 로직 수행과 메시지 발행을 하나의 트랜잭션으로 묶어서 메시지 유실을 원천 차단하는 패턴입니다.

  • 방법:

    • DB에 별도의 Outbox 테이블을 두고, 비즈니스 데이터와 메시지 데이터를 한 트랜잭션 안에서 저장한 뒤, 별도 프로세스가 메세지를 발행합니다.

2. 보상 트랜잭션 (Compensating Transaction)

  • 목적:

    • 이미 커밋된 트랜잭션을 취소할 수 없으므로, 결과를 상쇄시키는 반대 작업을 실행하여 논리적으로 롤백하는 패턴입니다.

  • 예시:

    • 주문 성공 → 재고 차감 성공 → 결제 실패 상황 발생 시, 이미 완료된 ‘주문’과 ‘재고 차감’을 취소하는 ‘주문 최소’, ‘재고 복구’ 요청을 수행하는 방식입니다. (Saga Pattern)

Last updated