摘要
RabbitMQ的发布者确认(Publisher Confirms)特性用以实现消息的可靠投递。当在某个通道(channel)上开启发布确认后,客户端发布的消息会被MQ服务器(broker)异步的确认。本篇主要介绍3个基于发布确认特性,保证被发布消息安全到达MQ服务器的方案,并比较各自优缺点。
开启发布者确认
发布者确认是RabbitMQ对AMQP 0.9.1协议的扩展,因此默认情况下未启用它们。发布者确认在通道级别使用confirmSelect
方法启用:
Channel channel = connection.createChannel();
channel.confirmSelect();
注意,每个需要开启的发布者确认的通道都必须调用此方法。开启后,发布消息时不需要再调用。
方案1:单条消息发布确认
这个方案是最简单明了的实现,即发布消息并同步等待其确认:
while (thereAreMessagesToPublish()) {
byte[] body = ...;
BasicProperties properties = ...;
channel.basicPublish(exchange, queue, properties, body);
// uses a 5 second timeout
channel.waitForConfirmsOrDie(5_000);
}
在发送一条消息后,我们通过Channel#waitForConfirmsOrDie(long)
方法等待该消息的确认。在确认消息后,该方法将立即返回;如果未在超时时间内确认该消息或该消息没有被确认(这意味着MQ服务器出于某种原因无法处理该消息),则该方法将抛出异常。异常的处理通常包括记录错误消息和重试发送消息。
此方案实现非常简单,容易理解,但有个主要缺点:由于确认方法阻塞了其他消息的发送,会显著降低消息发送的吞吐量。如果你的应用场景对消息吞吐量的要求不高(每秒不过百),那推荐使用这个方案。
发布者确认到底是同步的还是异步的?
可以把waitForConfiirmOrDie
方法看做是一个同步工具,它让客户端可以同步的方式执行。但背后是一个异步的过程,客户端是异步的接受MQ服务器的确认通知。
方案2: 批次发布消息并确认
为了提高吞吐量,我们可以先发送一个批次的消息,然后等待整个批次消息的确认:
int batchSize =