메시지가 브로커에 도달하지 않았거나 전송 중 네트워크 오류가 발생할 경우 메시지가 손실될 수 있습니다.
Java에서 메시지를 브로커로 전송을 하는데 그 과정에서 장애가 발생할 수 있다.
보통 메시지를 보내고 메시지가 큐에 정상적으로 저장이되었는지는 확인하지 않기때문에 이를 방지할 수 있는 Publisher Confirm
이라는 기능이 rabbitMQ에 존재한다.
Publisher Confirm 개념
큐에 저장된 메시지가 RabbitMQ 서버가 다운되거나 장애가 발생할 때 손실될 수 있습니다.
하단 2-1,2-2 참고
소비자가 메시지를 가져간 후 처리를 완료하기 전에 장애가 발생하면 메시지가 손실될 수 있습니다. 이 경우 자동으로 "ack"이 설정되어 있으면, RabbitMQ는 메시지가 성공적으로 처리되었다고 간주하고 삭제할 수 있습니다.
하단 2-3,2-4 참고
큐 자체를 내구성 있게 만듦으로써 RabbitMQ가 재시작되어도 큐가 유지됩니다. 큐를 선언할 때 durable 옵션을 true로 설정합니다.
channel.queueDeclare("queueName", true, false, false, null);
메시지를 지속적으로 저장해 서버 장애에도 메시지를 유실하지 않도록 합니다. 메시지를 보낼 때 MessageProperties.PERSISTENT_TEXT_PLAIN
옵션을 사용합니다.
channel.basicPublish("", "queueName", MessageProperties.PERSISTENT_TEXT_PLAIN, messageBody);
소비자가 메시지를 처리한 후 직접 RabbitMQ에 메시지 처리가 완료되었음을 알리는 방법입니다. 이를 통해 소비자가 처리 실패 시 메시지를 다시 큐에 남겨둘 수 있습니다.
channel.basicAck(deliveryTag, false); //메시지 처리가 성공됐음을 알림
//deliveryTag: RabbitMQ가 해당 메시지를 식별하는 고유 ID로, 어떤 메시지를 ack 처리할지
//지정하는 데 사용됩니다.
//false: 여러 메시지를 한꺼번에 처리할지 여부를 나타냅니다. false이면 해당 deliveryTag에
//해당하는 하나의 메시지만 ack 처리됩니다.
소비자가 처리하지 못한 메시지를 자동으로 다른 큐에 전달하여 유실을 방지할 수 있습니다. 이를 통해 일정 시간이 지나거나 재시도 실패한 메시지를 별도로 관리할 수 있습니다.
메시지 전송에 실패한 것은 이유가 잇는데 지속적으로 재전송을 하게되면 비효율적이기 때문이다.
따라서 최대 전송횟수를 정해두고 이를 초과하면 DLQ(전송 실패 메시지를 모아두는 큐) 에 넣는 방식이 효과적
각 방법이 해결하는 문제가 다르기 때문에, 최소한 두 가지 이상의 방법을 함께 사용하는 것이 바람직합니다.
Durable Queue
와 Persistent Message
를 함께 사용하면, 서버 재시작 시 메시지와 큐 모두가 안전하게 보존됩니다.
Manual Acknowledgment
와 함께 사용하면 소비자가 처리하지 않은 메시지가 안전하게 큐에 남게 됩니다.
이렇게 여러 가지 방법을 조합해서 사용하는 것이 이상적이며, 특정한 문제 상황에서도 메시지 유실을 최대한 방지할 수 있습니다.