이기종 트랜잭션과 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 | 실패 | 실패 | 일관성 유지 | 아무 작업도 완료되지 않음 |
- 시나리오 2와 3은 시스템 신뢰성을 크게 저하시킵니다.
- 특히 시나리오 3은 DB 커밋 실패 후 Kafka 전송을 재시도하는 잘못된 로직에서 발생할 수 있습니다.
Best-Effort Atomicity: 완벽하지 않지만 최선을 다한다
개념과 접근 방식
Best-Effort Atomicity는 완벽한 원자성을 포기하되, 최대한 근접하게 만드는 실용적 접근법입니다. 핵심 원칙은 다음과 같습니다:
- 우선순위 결정: 더 중요한 시스템의 트랜잭션을 우선 보장합니다. (예: DB 커밋을 최우선)
- 보상 작업(Compensating Action): 실패 시 후속 조치로 일관성을 복구합니다.
- 멱등성(Idempotency) 설계: 작업의 재시도가 부작용을 발생시키지 않도록 합니다.
시나리오별 Best-Effort 대응 전략
시나리오 | 문제점 | Best-Effort 해결책 |
---|---|---|
2 | Kafka 전송 실패 | Outbox 테이블에 이벤트 저장 → 별도 프로세스가 재전송 보장 |
3 | DB 실패 후 Kafka 성공 | DB 커밋 완료 후에만 Kafka 전송 → DB 실패 시 전송 자체를 시도하지 않음 |
Outbox 패턴
동작 원리
Outbox 패턴은 트랜잭션 로그 테이블을 활용해 이벤트 전달의 신뢰성을 높입니다.
구현 단계:
- Outbox 테이블 생성: DB 트랜잭션 내에서 이벤트를 저장합니다.
- 이벤트 릴레이 프로세스: 변경 사항을 감지해 Kafka에 전달합니다.
시나리오별 Outbox 패턴 동작
시나리오 | Outbox 패턴 동작 | 결과 |
---|---|---|
2 | Outbox 테이블에 이벤트 저장 → 릴레이 프로세스가 재시도하여 Kafka 전송 보장 | Eventually Consistent |
3 | DB 커밋 실패 → Outbox 테이블에 이벤트 기록되지 않음 → Kafka 전송 시도 자체 없음 | 일관성 유지 |
Best-Effort Atomicity와 Outbox 패턴의 시너지
Outbox 패턴은 Best-Effort 원칙을 구체화합니다:
- 트랜잭션 경계 일원화: DB 커밋 성공을 전제로 메시지 전달을 시도합니다.
- 재시도 메커니즘: 메시지 전달 실패 시 Outbox 테이블을 통해 자동 복구됩니다.
결론: “메시지 유실 vs. 시스템 중단, 어떤 리스크가 더 큰가?”
분산 시스템에서 이기종 트랜잭션의 완벽한 원자성을 보장하는 것은 기술적 복잡성과 비용이 큽니다. 비즈니스 요구사항에 맞는 일관성 수준을 선택하고, 실패를 견딜 수 있는 설계를 하는 것이 더 현명합니다.
핵심 원칙
Best-Effort Atomicity 수용
DB 커밋 성공을 기준으로 Kafka 메시지 전달을 시도합니다.
완벽함보다 부분 실패에 대한 복구 가능성을 우선합니다.
Outbox 패턴 활용
DB 트랜잭션 내에서 이벤트 저장 → 별도 프로세스가 Kafka 전달을 보장합니다.
DB와 Kafka의 트랜잭션 경계를 분리하여 결합도를 낮춥니다.
일관성 모델 명확히 정의
금융 시스템: 강한 일관성 (Saga/2PC)
대부분의 이벤트 기반 시스템: 최종 일관성 (Outbox + 재시도)
Outbox 패턴의 장점
신뢰성: DB 커밋 성공 시 이벤트 전송이 보장됩니다.
유연성: 메시징 시스템(Kafka, RabbitMQ 등) 교체 시 영향도가 낮습니다.
장애 복구: CDC 또는 배치 프로세스로 자동 복구가 가능합니다.
주의할 점
멱등성 처리: 메시지 중복 전송 시 부작용이 없도록 설계해야 합니다.
Outbox 테이블 관리: 이벤트 누적으로 인한 스토리지 부하를 모니터링합니다.