前言:在面试的时候如果你会用消息中间件,那么面试一般都会问到MQ是如何保证消息不丢失的这个问题,所以这个问题对于面试和日常工作都非常之重要,本文主要讲述RocketMQ是如何保证消息不丢失的,但是我们可以举一反三,任何消息中间件都可以从以下几个方面着手去考虑,加油!
要回答这个问题,首先我们需要先了解RocketMQ架构:
我们可以看到这个消息中间件的架构为生产阶段、存储阶段、消费阶段,
简化以下:
那么消息中间件的消息消息可能在哪些阶段丢失呢?
答案自然是生产阶段、存储阶段、消费阶段都有可能丢失。所以当我们考虑消息丢失的时候以下要从这三个阶段考虑:
在生产阶段,主要通过请求确认机制,来保证消息的可靠传递。
1、同步发送的时候,要注意处理响应结果和异常。如果返回响应OK,表示消息成功发送到了Broker,
如果响应失败,或者发生其它异常,都应该重试。
2、异步发送的时候,应该在回调方法里检查,如果发送失败或者异常,都应该进行重试。
3、如果发生超时的情况,也可以通过查询日志的API,来检查是否在Broker存储成功。
或者设置定时任务,定期去轮询处理超时任务。反正就是尽可能保证消息一定要让存储端接受到消息,而且他要告诉你他已经收到消息了。
ok,考虑完生产阶段我们继续考虑存储阶段!
在存储阶段,可以通过配置可靠性优先的 Broker 参数来避免因为宕机丢消息,简单说就是可靠性优先的场景都应该使用同步确认机制来保证。
1、消息只要持久化到CommitLog(日志文件)中,即使Broker宕机,未消费的消息也能重新恢复再消费。
2、Broker的刷盘机制:同步刷盘和异步刷盘,不管哪种刷盘都可以保证消息一定存储在pagecache中(内存中),
但是同步刷盘更可靠,它是Producer发送消息后等数据持久化到磁盘之后再返回响应给Producer。
3、Broker通过主从模式来保证高可用,Broker支持Master和Slave同步复制、Master和Slave异步复制模式,
生产者的消息都是发送给Master,但是消费既可以从Master消费,也可以从Slave消费。同步复制模式可以保证即使Master宕机,
消息肯定在Slave中有备份,保证了消息不会丢失。
OK,这是官方给的同步刷盘和异步刷盘的区别
从图中我们可以看出,同步刷盘策略是一定要写入磁盘成功以后才会返回ACK确认,而异步刷盘则是写入内存以后直接返回ACK确认,同步与异步相比虽然效率低一些,但是避免了因宕机导致消息丢失的风险。
解下来我们继续考虑在消费端如何保证消息的可靠性!
从Consumer角度分析,如何保证消息被成功消费?
1、Consumer保证消息成功消费的关键在于确认的时机,不要在收到消息后就立即发送消费确认,
而是应该在执行完所有消费业务逻辑之后,再发送消费确认。
因为消息队列维护了消费的位置,逻辑执行失败了,没有确认,再去队列拉取消息,就还是之前的一条。
2.可以采用消费端消费失败重试策略,设置消费失败重试次数,比如5次,RocketMQ天然支持消费失败重试,
到达失败重试次数以后还会将消息放入死信队列,供开发人员手动处理,这样就尽可能的保证消息在消费端
消费成功还不会影响系统性能。
RocketMQ消费重试时间间隔如下:
注意:消费次数是可以随便设置的,若重试次数超过16次,后面每次重试间隔都为2小时。
具体怎么设置请看我之前的博客如何在RocketMQ的消费端查看消息的消费次数?
这里面有写如何设置消费次数。
如果面试的时候能这么回答面试官,面试官肯定满意,觉得你小子有点东西,而且还不少!
最后:如果看到这里觉得对你有帮助,请点赞收藏加关注,你的每一次互动都是我持续更新的动力,十分感谢!