在项目中使用RabbitMQ时,我们可能会遇到这样的问题:如一个订单系统当用户付款成功时我们往消息中间件添加一条记录期望消息消费者修改订单状态,但是最终实际订单状态并没有被修改成功。遇到这种问题我们排查的思路如下:
1.消息是否已经成功发送到消息中间件 2.消息是否有丢失的情况 消息是否已经被消费成功 在生产环境下是不容许出现消息投递/消费错误的情况的,因为这可能会对企业产生巨大的损失,本博客将介绍RabbitMQ如何保证消息的可靠性.
对于RabbitMQ的Message的status,可能会有以下几种情况
那么对于这三种情况,我们分别要处理的问题也就是以下三个
我们一个一个来解决
为了保证消息被正确投递到消息中间件,RabbitMQ提供了如下两个配置来保证消息投递的可靠性。
如果消息和队列是可持久化的那么确认消息会将消息写入磁盘之后出,Broker回传给生产者的确认消息中DeliverTag域包含了确认消息的序列号,此外Broker也可以设置basic.ack的multiple域,表示到这个序列号之前的所有消息都已经得到了处理(multiple如果为true则表示小于等于deliveryTag的消息都被投递成功,如果为false则表示只有等于deliveryTag的消息已经被投递成功)
除了使用Publisher Confirm方式,RabbitMQ还提供了事务机制保证消息投递,但是使用事务会大大降低系统的吞吐量,就失去了消息中间件存在的意义,本博客不进行探讨。Publisher Confirm模式最大的好处在于他是异步的,一旦发布一条消息生产者应用程序就可以在等信道返回确认的同时继续发送下一条消息,当消息最终得到确认之后,生产者应用可以通过回调ACK方法来处理该确认消息,如果RabbitMQ因为自身内部错误导致消息丢失,生产者应用可以通过回调NACK方法来处理该确认消息
Publisher Confirm机制在性能上要比事务优越很多,但是Publisher Confirm机制无法进行回滚,一旦服务器崩溃生产者无法得到Confirm信息,生产者其实本身也不知道该消息是否已经被持久化,只有继续重发来保证消息不丢失,但是如果原先已经持久化的消息并不会被回滚,这样队列中就会存在两条相同的消息,系统需要支持去重
假设在运行过程中RabbitMQ服务端宕机了,若此前没有进行持久化操作则消息就会丢失。所以使用RabbitMQ通常建议开启持久化功能
默认情况下,如果Message 已经被某个Consumer正确的接收到了,那么该Message就会被从queue中移除。当然也可以让同一个Message发送到很多的Consumer。如果一个queue没被任何的Consumer Subscribe(订阅),那么,如果这个queue有数据到达,那么这个数据会被cache,不会被丢弃。当有Consumer时,这个数据会被立即发送到这个Consumer,这个数据被Consumer正确收到时,这个数据就被从queue中删除。
如何定义“正确收到”
在消费消息的时候手动使用channel.basicAck()进行消息确认,channel.basicNack()进行消息拒绝。
本章介绍了RabbitMQ如何保证消息的可靠性投递,看完了这些,想必你已经厉兵秣马,整装待发了,那么下一章,我们就一起来用Java,来做一个RabbitMQ的连接Demo
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。