basicPublish()가 예외 없이 정상 리턴했는데, 메시지가 브로커에 도달하지 못하는 경우가 있다면?

발행 확인 메커니즘: 트랜잭션과 게시자 확인

왜 발행 확인이 필요한가

소비자 측에서는 ACK/NACK를 통해 메시지 처리 결과를 브로커에 알릴 수 있습니다. 그렇다면 생산자가 발행한 메시지가 브로커에 정상적으로 도달했는지 는 어떻게 확인할 수 있을까요?

발행 확인 메커니즘 이란, 메시지를 브로커에 발행할 때 브로커가 해당 메시지를 정상적으로 수신 및 저장했는지 생산자(Producer)가 확인하는 절차입니다.

예외 처리만으로 충분하지 않은 이유

basicPublish() 호출 시 RabbitMQ 서버에 연결할 수 없으면 ConnectionException 같은 예외가 발생합니다. 그러나 예외가 발생하지 않아도 메시지가 유실되는 상황 이 존재합니다.

상황설명
네트워크 지연연결은 유지되지만 메시지가 브로커에 도달하지 못함
** 브로커 내부 오류**메시지를 수신했지만 디스크 저장 과정에서 실패
** 브로커 재시작**메시지 발행 직후 브로커가 재시작되어 메시지 유실

이러한 상황에서는 basicPublish()가 정상적으로 반환되어도 메시지가 실제로 브로커에 저장되지 않을 수 있습니다.

** 예외 처리 **는 네트워크/연결 레벨의 문제를 감지하고, ** 발행 확인 **은 메시지 저장 레벨의 문제를 감지합니다. 두 메커니즘은 ** 상호 보완적 **이며, 안정적인 메시지 발행을 위해서는 둘 다 활용해야 합니다.


두 가지 발행 확인 메커니즘

RabbitMQ는 두 가지 발행 확인 메커니즘을 제공하며, ** 두 모드는 상호 배타적 **입니다. 한 채널에서 하나만 사용할 수 있습니다.

비교 항목트랜잭션(Transaction)게시자 확인(Publisher Confirms)
** 처리 방식**동기적 (commit/rollback)비동기적 (ack/nack 콜백)
** 성능**느림 (매번 브로커 응답 대기)빠름 (비동기 응답으로 대량 처리 가능)
** 신뢰성**원자성 보장 (여러 메시지 일괄 성공/실패)개별 메시지 단위 확인 (원자성 없음)
** 사용 권장**원자적 처리가 필수인 특수 상황** 대부분의 실무 환경**
** 성능 영향**2~10배 처리량 감소미미한 성능 저하

트랜잭션 (Transaction)

트랜잭션이란

트랜잭션은 여러 메시지 발행 작업을 하나로 묶어, ** 모두 성공하거나 모두 실패 **하도록 보장하는 원자적 처리 방식입니다.

  • ** 원자성(Atomicity)**: 모든 작업이 성공하거나 모두 실패
  • ** 일관성(Consistency)**: 시스템 상태가 일관되게 유지
  • ** 격리성(Isolation)**: 동시 실행되는 트랜잭션이 서로 영향을 주지 않음
  • ** 지속성(Durability)**: 커밋된 트랜잭션은 영구적으로 저장

트랜잭션 동작 흐름

PLAINTEXT
txSelect()  →  basicPublish()  →  txCommit() (성공 시)
                                →  txRollback() (실패 시)

코드 예시

JAVA
ConnectionFactory factory = new ConnectionFactory();
factory.setHost("localhost");

try (Connection connection = factory.newConnection();
     Channel channel = connection.createChannel()) {

    channel.txSelect(); // 트랜잭션 시작

    try {
        channel.basicPublish("ex", "rk", null, "msg1".getBytes("UTF-8"));
        channel.basicPublish("ex", "rk", null, "msg2".getBytes("UTF-8"));
        channel.txCommit(); // 모든 메시지 발행 성공 → 커밋
    } catch (Exception e) {
        channel.txRollback(); // 하나라도 실패 → 전체 롤백
    }
}

트랜잭션의 한계

트랜잭션은 매 commit/rollback마다 ** 브로커의 동기적 응답을 기다려야** 하므로, 처리량이 크게 감소합니다. RabbitMQ 공식 문서에서도 대부분의 경우 Publisher Confirms를 권장합니다.


게시자 확인 (Publisher Confirms)

게시자 확인이란

게시자 확인은 메시지를 발행한 후 브로커가 해당 메시지를 정상적으로 처리했는지 ** 비동기로 알려주는 기능 **입니다. 트랜잭션보다 가볍고 빠른 메시지 신뢰성 확보 방법입니다.

동작 원리

  1. 채널에서 confirm 모드를 활성화합니다.
  2. 이후 발행되는 모든 메시지에 ** 시퀀스 번호 **가 자동 부여됩니다.
  3. 브로커가 메시지를 정상 처리하면 ack, 실패하면 nack를 응답합니다.

Step 1: 확인 모드 활성화

JAVA
channel.confirmSelect();

한 번 confirm 모드가 되면 트랜잭션 모드로 전환할 수 없으며, 그 반대도 마찬가지입니다.

Step 2: 비동기 확인 처리 (권장)

JAVA
channel.addConfirmListener(new ConfirmListener() {
    @Override
    public void handleAck(long deliveryTag, boolean multiple) throws IOException {
        // deliveryTag까지의 메시지 발행 성공 처리
        // multiple=true이면 deliveryTag 이하의 모든 메시지를 일괄 확인
    }

    @Override
    public void handleNack(long deliveryTag, boolean multiple) throws IOException {
        // deliveryTag까지의 메시지 발행 실패 처리
        // 재발행 로직, 로깅, 알림 등 수행
    }
});

// 메시지 발행
channel.basicPublish(exchange, routingKey, props, body);

비동기 방식은 브로커의 응답을 기다리지 않고 ** 계속 메시지를 발행 **할 수 있으므로, 대량 메시지 처리에 최적입니다.

Step 3: 동기 확인 처리 (간단한 경우)

JAVA
channel.basicPublish(exchange, routingKey, props, body);

try {
    channel.waitForConfirmsOrDie(); // 모든 메시지의 ack/nack 응답을 동기적으로 대기
} catch (IOException e) {
    // nack 또는 타임아웃 발생 → 메시지 재발행, 로깅 등
}

waitForConfirmsOrDie()는 모든 메시지가 ack되면 정상 종료하고, 하나라도 nack이 발생하거나 응답이 오지 않으면 IOException을 던집니다.

동기 방식은 구현이 간단하지만 대량 처리에는 비동기 방식이 더 효율적입니다.


트랜잭션 vs 게시자 확인 선택 가이드

판단 기준트랜잭션 선택게시자 확인 선택
여러 메시지의 원자성이 필수OX
대량 메시지 처리가 필요XO
성능이 중요한 환경XO
구현 복잡도를 낮추고 싶음O (동기 흐름)비동기 시 다소 복잡
PLAINTEXT
메시지 발행 확인이 필요한가?
├─ No → 예외 처리만으로 충분
└─ Yes → 여러 메시지의 원자성이 필요한가?
         ├─ Yes → 트랜잭션 (txSelect/txCommit)
         └─ No → 게시자 확인 (confirmSelect)
                 ├─ 대량 처리 → 비동기 (addConfirmListener)
                 └─ 소량 처리 → 동기 (waitForConfirmsOrDie)

요약

대부분의 실무 환경에서는 ** 게시자 확인(Publisher Confirms)**을 사용하는 것을 권장합니다. 트랜잭션은 여러 메시지의 원자적 처리가 반드시 필요한 특수한 상황(금융, 결제 배치 등)에서만 선택합니다.

메커니즘핵심 특징
** 트랜잭션**원자성 보장, 동기적, 성능 저하 큼
** 게시자 확인 (비동기)**개별 확인, 높은 성능, 대량 처리 적합
** 게시자 확인 (동기)**간단한 구현, 소량 처리 적합

** 공식 문서 참고 **: Consumer Acknowledgements and Publisher Confirms

댓글 로딩 중...