발행 기록 패턴

Outbox는 업무 변경과 메시지 기록을 한 트랜잭션에 묶는다

브로커 전송까지 강제로 한 커밋에 넣지 않고, DB 안에 발행해야 할 이벤트를 남긴 뒤 릴레이와 소비자 멱등성으로 전달 실패를 흡수한다.

업무 변경 Outbox 기록 릴레이 재시도 브로커 전달 소비자 멱등성
원자성 업무 행과 발행 기록은 같은 DB 커밋 안에서 같이 확정된다.
반복성 릴레이는 실패와 응답 유실을 전제로 같은 기록을 다시 읽는다.
흡수 최종 안전성은 소비자의 처리 이력과 유니크 키에서 완성된다.

서비스 DB의 로컬 트랜잭션

원자성
업무 orders.status = 결제완료
사용자가 기대하는 실제 상태 변경
기록 event_id = evt_9421
발행할 이벤트와 payload를 같은 커밋에 저장

릴레이의 반복 발행

재시도
1 미발행 조회 상태가 대기인 이벤트를 작은 묶음으로 읽는다.
2 브로커 전송 응답이 불명확하면 같은 이벤트를 다시 보낼 수 있다.
3 발행 상태 갱신 성공이 확인된 뒤 전송 완료 시각을 남긴다.

소비자의 중복 흡수

멱등성
ID evt_9421 처리 이력 확인
이미 처리한 이벤트면 업무 변경을 반복하지 않는다.
결과 최종 상태 한 번만 반영
최소 1회 전달을 전제로 같은 결과를 유지한다.
커밋 전 실패 업무 변경과 이벤트 기록이 함께 롤백된다.
커밋 후 미발행 outbox 대기 행을 릴레이가 다시 읽는다.
응답 유실 같은 event_id가 다시 나갈 수 있음을 전제로 둔다.
소비자 중복 처리 이력과 유니크 키가 최종 방어선이다.
구간 보장하는 것 남는 위험 필요한 설계
DB 커밋 업무 변경과 이벤트 기록 동시 확정 브로커 전송은 아직 일어나지 않음 outbox 테이블, 이벤트 ID, 상태 컬럼
릴레이 실패한 전송을 계속 재시도 같은 메시지가 두 번 나갈 수 있음 잠금 조회, 배치 크기, 재시도 지연
소비자 처리 이력으로 중복 이벤트 식별 멱등성이 없으면 중복 반영 유니크 키, 처리 로그, 동일 응답 보관
2PC 대체가 아니라 결합도 완화

DB와 브로커를 하나의 커밋으로 묶지 않는 대신 재시도 가능한 기록을 남긴다.

전달은 최소 1회로 본다

릴레이 장애와 응답 유실 때문에 중복 발행 가능성을 정상 조건으로 둔다.

소비자 멱등성이 완성 조건

event_id 기반 처리 이력이 없으면 Outbox만으로 최종 일관성이 보장되지 않는다.