Post

이기종 트랜잭션과 Best-Effort Atomicity

이기종 트랜잭션과 Best-Effort Atomicity

Intro

분산 시스템의 트랜잭션 관리 복잡성

분산 시스템에서는 데이터베이스(DB), 메시지 큐(Kafka), 캐시 서버 등 이기종 시스템 간 협력이 필수적입니다. 이때 트랜잭션의 원자성(Atomicity)을 보장하는 것은 큰 과제입니다. 특히 DB 업데이트와 Kafka 메시지 발행을 동시에 수행해야 할 때, 두 시스템의 트랜잭션 경계를 일관되게 유지하지 못하면 데이터 불일치가 발생합니다. 이 글에서는 Best-Effort Atomicity 개념을 통해 이기종 트랜잭션 문제를 해결하고, Outbox 패턴으로 실전 적용하는 방법을 설명합니다.


이기종 트랜잭션의 문제점

정의와 핵심 이슈

이기종 트랜잭션(Heterogeneous Transaction)은 서로 다른 기술 스택을 가진 시스템(예: RDBMS와 Kafka)이 하나의 논리적 작업 단위로 동작해야 하는 상황을 의미합니다. 예를 들어, “주문 생성(DB)”과 “주문 이벤트 발행(Kafka)”을 동시에 수행해야 할 때 다음 문제가 발생합니다:

  • 트랜잭션 경계 불일치: DB는 ACID 트랜잭션을 지원하지만 Kafka는 메시지 전달 보장 수준이 다릅니다.
  • 부분 실패(Partial Failure): DB 커밋은 성공했으나 Kafka 메시지 발행이 실패하면 시스템 상태가 불일치합니다.

시나리오별 문제 분석

다음은 DB와 Kafka 간 트랜잭션 조합에 따른 시스템 상태를 정리한 표입니다.

시나리오DB 커밋 결과Kafka 전송 결과시스템 상태비고
1성공성공일관성 유지이상적인 경우
2성공실패데이터 불일치주문은 생성됐으나 이벤트 유실 → 다른 서비스가 주문 정보를 인식 불가
3실패성공데이터 불일치 (심각한 문제)주문은 없는데 이벤트 존재 → 잘못된 비즈니스 프로세스 유발
4실패실패일관성 유지아무 작업도 완료되지 않음
  • 시나리오 23은 시스템 신뢰성을 크게 저하시킵니다.
  • 특히 시나리오 3은 DB 커밋 실패 후 Kafka 전송을 재시도하는 잘못된 로직에서 발생할 수 있습니다.

Best-Effort Atomicity: 완벽하지 않지만 최선을 다한다

개념과 접근 방식

Best-Effort Atomicity는 완벽한 원자성을 포기하되, 최대한 근접하게 만드는 실용적 접근법입니다. 핵심 원칙은 다음과 같습니다:

  1. 우선순위 결정: 더 중요한 시스템의 트랜잭션을 우선 보장합니다. (예: DB 커밋을 최우선)
  2. 보상 작업(Compensating Action): 실패 시 후속 조치로 일관성을 복구합니다.
  3. 멱등성(Idempotency) 설계: 작업의 재시도가 부작용을 발생시키지 않도록 합니다.

시나리오별 Best-Effort 대응 전략

시나리오문제점Best-Effort 해결책
2Kafka 전송 실패Outbox 테이블에 이벤트 저장 → 별도 프로세스가 재전송 보장
3DB 실패 후 Kafka 성공DB 커밋 완료 후에만 Kafka 전송 → DB 실패 시 전송 자체를 시도하지 않음

Outbox 패턴

동작 원리

Outbox 패턴은 트랜잭션 로그 테이블을 활용해 이벤트 전달의 신뢰성을 높입니다.

구현 단계:

  1. Outbox 테이블 생성: DB 트랜잭션 내에서 이벤트를 저장합니다.
  2. 이벤트 릴레이 프로세스: 변경 사항을 감지해 Kafka에 전달합니다.

시나리오별 Outbox 패턴 동작

시나리오Outbox 패턴 동작결과
2Outbox 테이블에 이벤트 저장 → 릴레이 프로세스가 재시도하여 Kafka 전송 보장Eventually Consistent
3DB 커밋 실패 → Outbox 테이블에 이벤트 기록되지 않음 → Kafka 전송 시도 자체 없음일관성 유지

Best-Effort Atomicity와 Outbox 패턴의 시너지

Outbox 패턴은 Best-Effort 원칙을 구체화합니다:

  • 트랜잭션 경계 일원화: DB 커밋 성공을 전제로 메시지 전달을 시도합니다.
  • 재시도 메커니즘: 메시지 전달 실패 시 Outbox 테이블을 통해 자동 복구됩니다.

결론: “메시지 유실 vs. 시스템 중단, 어떤 리스크가 더 큰가?”

분산 시스템에서 이기종 트랜잭션의 완벽한 원자성을 보장하는 것은 기술적 복잡성과 비용이 큽니다. 비즈니스 요구사항에 맞는 일관성 수준을 선택하고, 실패를 견딜 수 있는 설계를 하는 것이 더 현명합니다.

핵심 원칙

  1. Best-Effort Atomicity 수용

    • DB 커밋 성공을 기준으로 Kafka 메시지 전달을 시도합니다.

    • 완벽함보다 부분 실패에 대한 복구 가능성을 우선합니다.

  2. Outbox 패턴 활용

    • DB 트랜잭션 내에서 이벤트 저장 → 별도 프로세스가 Kafka 전달을 보장합니다.

    • DB와 Kafka의 트랜잭션 경계를 분리하여 결합도를 낮춥니다.

  3. 일관성 모델 명확히 정의

    • 금융 시스템: 강한 일관성 (Saga/2PC)

    • 대부분의 이벤트 기반 시스템: 최종 일관성 (Outbox + 재시도)

Outbox 패턴의 장점

  • 신뢰성: DB 커밋 성공 시 이벤트 전송이 보장됩니다.

  • 유연성: 메시징 시스템(Kafka, RabbitMQ 등) 교체 시 영향도가 낮습니다.

  • 장애 복구: CDC 또는 배치 프로세스로 자동 복구가 가능합니다.

주의할 점

  • 멱등성 처리: 메시지 중복 전송 시 부작용이 없도록 설계해야 합니다.

  • Outbox 테이블 관리: 이벤트 누적으로 인한 스토리지 부하를 모니터링합니다.

This post is licensed under CC BY 4.0 by the author.