1. 消息确认机制以及事务机制
- 通过AMQP协议保证事务机制的实现;简称
tx机制
- 通过设置channel 为 confirm 模式来实现;简称
confirm机制
1.1 tx模式:
- txSelect() 用于将当前 channel 设置成 transaction 模式(开启事务);
- txCommit 用于提交事务;
- txRollback 用于回滚事务;
对应代码:
channel.txSelect();
channel.txCommit();
channel.txRollback();
举例说明:
发送方代码:
// 建立链接,声明通道代码...
try {
//开启事务
channel.txSelect();
//业务逻辑代码
//发送消息
channel.basicPublish("", queue_name, null, string.getBytes());
//模拟异常操作
//int a = 10/0;
//无异常 正常执行,则提交事务操作
channel.txCommit();
} catch (Exception e) {
System.out.println("出现异常 回滚操作");
channel.txRollback();
}
//5、关流代码...
事务模块吞吐量不行,是同步的一种阻塞机制;
1.2 Confirm模式:
-
生产者端,confirm模式的实现原理
- 生产者将信道(channel)设置为confirm模式。
- 所有在该信道上发布的消息,都会指派一个起始为1且唯一的id,一旦消息被推送至匹配的队列之后,broker就会发送一个(携带id的)确认给生产者,使得生产者知道消息成功到达了目标队列中。
- 如果消息和队列是可持久化(durable = true)的,那么 确认消息 会将消息写至磁盘后发出。
- broker回传给生产者的确认消息中deliver-tag域包含了确认消息的序列号,此外broker也可以设置basic.ack的multiple域,表示这个序列号之前的所有消息都已经得到了处理。
-
confirm模式的优势
confirm 模式最大的好处在于他是异步的。
一旦发布一条消息,生产者应用程序就可以在等信道返回确认的同时继续发送下一条消息,当消息最终得到确认之后,生产者应用便可以通过回调方法来处理该确认消息,如果RabbitMQ 因为自身内部错误导致消息丢失,就会发送一条 nack 消息,生产者应用程序同样可以在回调方法中处理该 nack 消息。 -
开启confirm模式
://生产者调用channel的confirmSelect()将信道设置为confirm模式。
channel.confirmSelect();
注意: 已经在 transaction 事务模式的 channel 是不能再设置成 confirm 模式的。因为两者不可并存;
发送方代码:
// 建立链接,声明通道代码...
// 开启confirm
channel.confirmSelect();
//业务逻辑代码
//发送消息
channel.basicPublish("", queue_name, null, string.getBytes());
//5、关流代码...
发布确认影响性能:confirm机制对性能的影响 < tx机制对性能的影响
2. 简单列子
2.1 消息发送端
- confirm机制
channel.ConfirmSelect();
channel.BasicPublish("headersExchange", string.Empty, properties, Encoding.UTF8.GetBytes("来自.net的问候"));
var isAllPublished = channel.WaitForConfirms();
- tx机制
try {
//发布消息
//String exchange, 交换机名称
//String routingKey, routingKey
//IBasicProperties basicProperties, 发布属性
//Byte[] body 消息内容
channel.TxSelect();
channel.BasicPublish("headersExchange", string.Empty, properties, Encoding.UTF8.GetBytes("来自.net的问候"));
channel.TxCommit();
} catch (Exception) {
channel.TxRollback();
}
2.2 消息消费端
- 自动确认:消息出队列的时候就自动确认
- 手动确认:消息出队列之后,要应用程序自己去确认是否已经消费完毕,如果消费端拿到消息之后没有手动确认,这个时候消息不会被丢失。
//直接获取消息
//String queue, 队列名称
//Boolean autoAck 是否自动确认(一般设置为true)
var result = channel.BasicGet("headersQueue", false);
//手动确认
//UInt64 deliveryTag,
//Boolean multiple 结果是否为多条数据
channel.BasicAck(result.DeliveryTag, false)
- 手动拒绝: 消费端拒绝队列发送过来的消息
//直接获取消息
//String queue, 队列名称
//Boolean autoAck 是否自动确认(一般设置为true)
var result = channel.BasicGet("headersQueue", false);
//手动确认
//UInt64 deliveryTag,
//Boolean multiple 结果是否为多条数据
channel.BasicAck(result.DeliveryTag, false);
//手动拒绝(单个)
//UInt64 deliveryTag,
//Boolean requeue 是否重新放回队列,true==是,false==丢弃
channel.BasicReject(result.DeliveryTag, true);
//手动拒绝(单或多均可)
//UInt64 deliveryTag,
//Boolean multiple, 是否多条数据
//Boolean requeue 是否重新放回队列,true==是,false==丢弃
channel.BasicNack(result.DeliveryTag, false, true);
//重新递送
//Boolean requeue true==重新入队列,可能会被其他消费者所接收;false==重新给当前消费者递送
channel.BasicRecover(false);