1. 概述
在消息代理(如RabbitMQ),由于发送消息的AMQP协议方法不能保证消息一定到达对方或被成功处理,所以发布者和消费者都需要一个交付和处理确认的机制。 在上一篇文章中间件系列十 RabbitMQ之消费者端的消息确认机制,我们介绍了消费端的消息确认机制。本篇我们介绍发送端的消息确认机制
RabbitMQ在收到消息后,还需要有一段时间才能将消息存入磁盘之中。RabbitMQ并不是为每条消息都做fsync的处理,可能仅仅保存到cache中而不是物理磁盘上,在这段时间内RabbitMQ broker发生crash, 消息保存到cache但是还没来得及落盘,那么这些消息将会丢失。为了解决这个问题RabbitMQ引入发送端消息确认机制,主要通过事务和publisher Confirm机制。
本篇的主要内容如下:
1. 通过AMQP事务和publisher Confirm机制保证发送端的消息不丢失
2. 演示RabbitMQ中的事务用法,并通过抓包分析协议,最后说明事务的事务的优点和缺点
3. 演示RabbitMQ中Publisher Confirm模式的用法,并对以下3种方式通过抓包分析协议并说明其缺点和优点
- 同步方式的发送端的单个Publisher Confirm模式
- 同步方式的发送端的批量Publisher Confirm机制
- 异步方式的发送端的Publisher Confirm机制
4. 其他发送者端的注意事项: 否定确认、消息确认的时机、持久化消息的确认延迟、发送顺序
2. 事务机制保证消息不丢失
RabbitMQ支持事务(transaction),通过调用tx.select方法开启事务模式。当开启了事务模式后,只有当一个消息被所有的镜像队列保存完毕后,RabbitMQ才会调用tx.commit-ok返回给客户端。
2.1. 代码
工程名称:rabbitmq
发送端的关键代码TransactionalSend:通过channel.txSelect()开启事务,发送消息,最后执行channel.txCommit()提交事务。如果发送失败,则使用channel.txRollback()回滚事务
// 开启事务
channel.txSelect();
// 发送消息
while(num-- > 0) {
// 发送一个持久化消息到特定的交换机
channel.basicPublish(EXCHANGE_NAME, routingKey, MessageProperties.PERSISTENT_TEXT_PLAIN, message.getBytes("UTF-8"));
System.out.println(" [TransactionalSend] Sent + [" + num + "] '" + message + "'");
}
// 不注解下面语句,可以进入channel.txRollback()逻辑
// if(true){
// throw new IOException("consumer channel.txRollback() ");
// }
// 提交事务
channel.txCommit();
}catch(IOException e){
e.printStackTrace();
// 回滚事务
channel.txRollback();
}
测试代码:使用PublisherConfirmTest的方法进行测试
2.2. 使用wireshark抓包分析正常的事务提交流程
使用wireshark截获以上测试时产生的包:
所有的包:
全部包如下:
496-497帧:开启事务
496帧:Tx.Select 客户端向RabbitMQ要求开启事务