RabbitMQ消息可靠性分析
消息中间件的可靠性是指对消息不丢失的保障程度;而消息中间件的可用性是指无故障运行的时间百分比,通常用几个 9 来衡量。不存在绝对的可靠性只能尽量趋向完美。并且通常可靠性也意味着影响性能和付出更大的成本,因此实际应用时还要根据业务需求,对真正关键的信息来做可靠性保证,并要从生产者、消息队列、消费者三个维度来努力。
1、生产者发送信息的可靠性
生产者客户端发送出去之后可以发生网络丢包、网络故障等造成消息丢失。一般情况下如果不采取措施,生产者无法感知消息是否已经正确无误的发送到交换器中。如果消息在传输到Exchange的过程中发生失败而可以让生产者感知的话,生产者可以进行进一步的处理动作,比如重新投递相关消息以确保消息的可靠性。为此AMQP协议在建立之初就考虑到这种情况而提供了事务机制。
事务确实能够解决消息发送方和RabbitMQ之间消息确认的问题,只有消息成功被RabbitMQ接收,事务才能提交成功,否则我们便可在捕获异常之后进行事务回滚,与此同时可以进行消息重发。但是使用事务机制的话会“吸干”RabbitMQ的性能,那么有没有更好的方法既能保证消息发送方确认消息已经正确送达,又能基本上不带来性能上的损失呢?从AMQP协议层面来看并没有更好的办法,但是RabbitMQ提供了一个改进方案,即发送方确认机制(publisher confirm)。事务机制在一条消息发送之后会使发送端阻塞,以等待RabbitMQ的回应,之后才能继续发送下一条消息。相比之下,发送方确认机制最大的好处在于它是异步的,一旦发布一条消息,生产者应用程序就可以在等信道返回确认的同时继续发送下一条消息,当消息最终得到确认之后,生产者应用便可以通过回调方法来处理该确认消息,如果RabbitMQ因为自身内部错误导致消息丢失,就会发送一条nack(Basic.Nack)命令,生产者应用程序同样可以在回调方法中处理该nack命令。事务机制和publisher confirm机制两者是互斥的,不能共存。
2、消息路由到队列的可靠性
消息发送到交换器,如果没有和它匹配队列的话,消息也会丢失,mandatory或者AE可以让消息在路由到队列之前得到极大的可靠性保障。当mandatory参数设为true时,交换器无法根据自身的类型和路由键找到一个符合条件的队列的话,那么RabbitMQ会调用Basic.Return命令将消息返回给生产者。当mandatory参数设置为false时,出现上述情形的话,消息直接被丢弃。
备份交换器,英文名称Alternate Exchange,简称AE,或者更直白的可以称之为“备胎交换器”。生产者在发送消息的时候如果不设置mandatory参数,那么消息在未被路由的情况下将会丢失,如果设置了mandatory参数,那么需要添加ReturnListener的编程逻辑,生产者的代码将变得复杂化。如果你不想复杂化生产者的编程逻辑,又不想消息丢失,那么可以使用备份交换器,这样可以将未被路由的消息存储在RabbitMQ中,再在需要的时候去处理这些消息。 可以通过在声明交换器(调用channel.exchangeDeclare方法)的时候添加alternate-exchange参数来实现,也可以通过策略的方式实现。如果两者同时使用的话,前者的优先级更高,会覆盖掉Policy的设置。
3、消息在队列中持久化
持久化可以提高队列的可靠性,以防在异常情况(重启、关闭、宕机等)下的数据丢失。队列的持久化是通过在声明队列时将durable参数置为true实现的,如果队列不设置持久化,那么在RabbitMQ服务重启之后,相关队列的元数据将会丢失,此时数据也会丢失。
队列的持久化能保证其本身的元数据不会因异常情况而丢失,但是并不能保证内部所存储的消息不会丢失。要确保消息不会丢失,需要将其设置为持久化。通过将消息的投递模式(BasicProperties中的deliveryMode属性)设置为2即可实现消息的持久化。
如果在发送消息时采用了事务机制或者publisher confirm机制的话,服务端的返回是在消息落盘之后执行的,这样可以进一步的提高了消息的可靠性。但是即便如此也无法避免单机故障且无法修复(比如磁盘损毁)而引起的消息丢失,这里就需要引入镜像队列。镜像队列相当于配置了副本,绝大多数分布式的东西都有多副本的概念来确保HA。在镜像队列中,如果主节点(master)在此特殊时间内挂掉,可以自动切换到从节点(slave),这样有效的保证了高可用性,除非整个集群都挂掉。虽然这样也不能完全的保证RabbitMQ消息不丢失(比如机房被炸。。。),但是配置了镜像队列要比没有配置镜像队列的可靠性要高很多,在实际生产环境中的关键业务队列一般都会设置镜像队列。
4、消息消费阶段的可靠性
为了保证消息从队列可靠地达到消费者,RabbitMQ提供了消息确认机制(message acknowledgement)。消费者在订阅队列时,可以指定autoAck参数,当autoAck等于false时,RabbitMQ会等待消费者显式地回复确认信号后才从内存(或者磁盘)中移去消息(实质上是先打上删除标记,之后再删除)。当autoAck等于true时,RabbitMQ会自动把发送出去的消息置为确认,然后从内存(或者磁盘)中删除,而不管消费者是否真正的消费到了这些消息。RabbitMQ不会为未确认的消息设置过期时间,它判断此消息是否需要重新投递给消费者的唯一依据是消费该消息的消费者连接是否已经断开,这么设计的原因是RabbitMQ允许消费者消费一条消息的时间可以很久很久。
如果消息消费失败,也可以调用Basic.Reject或者Basic.Nack来拒绝当前消息而不是确认,如果只是简单的拒绝那么消息会丢失,需要将相应的requeue参数设置为true,那么RabbitMQ会重新将这条消息存入队列,以便可以发送给下一个订阅的消费者。如果requeue参数设置为false的话,RabbitMQ立即会把消息从队列中移除,而不会把它发送给新的消费者。
还有一种情况需要考虑: requeue的消息是存入队列头部的,即可以快速的又被发送给消费,如果此时消费者又不能正确的消费而又requeue的话就会进入一个无尽的循环之中。对于这种情况,笔者的建议是在出现无法正确消费的消息时不要采用requeue的方式来确保消息可靠性,而是重新投递到新的队列中,比如设定的死信队列中,以此可以避免前面所说的死循环而又可以确保相应的消息不丢失。对于死信队列中的消息可以用另外的方式来消费分析,以便找出问题的根本。
RabbitMQ消息可靠性分析的更多相关文章
- RabbitMQ消息可靠性分析和应用
RabbitMQ流程简介(带Exchange) RabbitMQ使用一些机制来保证可靠性,如持久化.消费确认及发布确认等. 先看以下这个图: P为生产者,X为中转站(Exchange),红色部分为消息 ...
- RabbitMQ消息可靠性分析 - 简书
原文:RabbitMQ消息可靠性分析 - 简书 有很多人问过我这么一类问题:RabbitMQ如何确保消息可靠?很多时候,笔者的回答都是:说来话长的事情何来长话短说.的确,要确保消息可靠不只是单单几句就 ...
- [转载]RabbitMQ消息可靠性分析
有很多人问过我这么一类问题:RabbitMQ如何确保消息可靠?很多时候,笔者的回答都是:说来话长的事情何来长话短说.的确,要确保消息可靠不只是单单几句就能够叙述明白的,包括Kafka也是如此.可靠并不 ...
- RabbitMQ消息可靠性传输
消息的可靠性投递是使用消息中间件不可避免的问题,不管是使用kafka.rocketMQ或者rabbitMQ,那么在RabbitMQ中如何保证消息的可靠性投递呢? 先再看一下RabbitMQ消息传递的流 ...
- RabbitMQ消息可靠性、死信交换机、消息堆积问题
目录 消息可靠性 生产者消息确认 示例 消费者消息确认 示例 死信交换机 例子 高可用问题 消息堆积问题 惰性队列 参考 消息可靠性 确保消息至少被消费了一次(不丢失) 消息丢失的几种情况: 消息在网 ...
- RabbitMQ消息可靠性
那些情况会失败 网络问题有很多原因出发失败.防火墙也可能会中断Idle连接,网络失败不是很快确定的. 硬件和软件也会导致系统崩溃.客户端软件保持运行,而逻辑错误也可能会导致channel和connec ...
- 消息中间件-RabbitMQ消息可靠性和插件化机制
package com.study.rabbitmq.a132.confirm; import com.rabbitmq.client.*; import java.io.IOException; i ...
- 解决RabbitMQ消息丢失问题和保证消息可靠性(一)
原文链接(作者一个人):https://juejin.im/post/5d468591f265da03b810427e 工作中经常用到消息中间件来解决系统间的解耦问题或者高并发消峰问题,但是消息的可靠 ...
- SpringCloud之RabbitMQ消息队列原理及配置
本篇章讲解RabbitMQ的用途.原理以及配置,RabbitMQ的安装请查看SpringCloud之RabbitMQ安装 一.MQ用途 1.同步变异步消息 场景:用户下单完成后,发送邮件和短信通知. ...
随机推荐
- Angular2 -- 生命周期
组件生命周期钩子 指令和组件的实例有一个生命周期:新建.更新和销毁. 每个接口都有唯一的一个钩子方法,它们的名字是由接口名加上 ng前缀构成的.比如,OnInit接口的钩子方法叫做ngOnInit. ...
- 检测Linux glibc幽灵漏洞和修补漏洞
1.首先安装rpm : sudo apt-get install rpm wget -OGHOST-test.sh http://www.antian365.com/lab/linux0day/G ...
- Couchbase集群
Couchbase集群 http://www.cnblogs.com/sunwubin/p/3426801.html Couchbase服务器可以单独运行,也可以作为集群运行.在Couchbase集群 ...
- Sunday算法[原创]
一.应用: 同样的,sunday算法也是在一个字符串中查找另一个字符串出现的首地址,是Daniel M.Sunday于1990年提出的,从销量上讲,Sunday>BM>KMP,是这类问题的 ...
- yum安装docker报 No package docker available错误
解决方案: yum install epel-release 然后再安装 CentOS6 yum install http://mirrors.yun-idc.com/epel/6/i386/epel ...
- OC 设计模式
设计模式 一种或几种被所有程序员广泛认同的,有某些特定功能,或者实现某些特殊作用的编码格式 单例模式 键值编码(KVC) 键值观察(KVO) 观察者模式() 工厂模式(工厂方法) ps:MVC &am ...
- (转)RocketMQ源码学习--消息存储篇
http://www.tuicool.com/articles/umQfMzA 1.序言 今天来和大家探讨一下RocketMQ在消息存储方面所作出的努力,在介绍RocketMQ的存储模型之前,可以先探 ...
- javaScript面向对象是什么?(一)
js就是个面向对象语言,一切皆对象 一.什么是面向对象? 简单点,就这么说吧.生活中有一些个物品,譬如(哈哈,还想起个譬如)说一个iPhone,我们也不知道里面的工作原理吧?但是咱们会按按钮呀,用一俩 ...
- Vue--关于点击当前路由,视图无法更新的解决方案
转自:https://juejin.im/post/593121aa0ce4630057f70d35 问题的根源: 用户点击当前高亮的路由并不会刷新view,因为vue-router会拦截你的路由,它 ...
- Vue--Vue.nextTick()的使用
Vue.nextTick()是比较常用到的API Vue官网对它的解释是:在下次 DOM 更新循环结束之后执行延迟回调.在修改数据之后立即使用这个方法,获取更新后的 DOM. 首先要明白Vue的响应式 ...