目录
Producer发送消息阶段
手段一:提供SYNC的发送消息方式,等待broker处理结果。
手段二:发送消息如果失败或者超时,则重新发送。
手段三:broker提供多master模式
总结
Broker处理消息阶段
手段四:提供同步刷盘的策略【等待刷盘成功才会返回producer成功】
手段五:提供主从模式,同时主从支持同步双写
总结
Consumer消费消息阶段
手段六:consumer默认提供的是At least Once机制
手段七:消费消息重试机制
总结
发送消息阶段涉及到Producer到broker的网络通信,因此丢失消息的几率一定会有,那RocketMQ在此阶段用了哪些手段保证消息不丢失了(或者说降低丢失的可能性)。
RocketMQ提供了3种发送消息方式,分别是:
同步发送:Producer 向 broker 发送消息,阻塞当前线程等待 broker 响应 发送结果。
异步发送:Producer 首先构建一个向 broker 发送消息的任务,把该任务提交给线程池,等执行完该任务时,回调用户自定义的回调函数,执行处理结果。
Oneway发送:Oneway 方式只负责发送请求,不等待应答,Producer只负责把请求发出去,而不处理响应结果。
我们在调用producer.send方法时,不指定回调方法,则默认采用同步发送消息的方式,这也是丢失几率最小的一种发送方式(但是效率比较低)。
发送重试源码如下,本质其实就是一个for循环,当发送消息发生异常或超时的时候重新循环发送。默认重试3次,重试次数可以通过producer指定。
即使某台broker宕机了,保证消息可以投递到另外一台正常的broker上。
如果broker只有一个节点,则broker宕机了,即使producer有重试机制,也没用(Broker都挂了,哪来的重试机制),因此利用多主模式,当某台broker宕机了,换一台broker进行投递,保持高可用。
producer消息发送方式虽然有3种,但为了减小丢失消息的可能性尽量采用同步的发送方式,同步等待发送结果,利用同步发送+重试机制+多个master节点,尽可能减小消息丢失的可能性。
public enum FlushDiskType { SYNC_FLUSH, //同步刷盘 ASYNC_FLUSH//异步刷盘(默认) }
我们知道,当消息投递到broker之后,会先存到page cache【页面缓存】,然后根据broker设置的刷盘策略是否立即刷盘,也就是如果刷盘策略为异步,broker并不会等待消息落盘才返回producer一个成功的消息,也就是说当broker所在的服务器突然宕机,则会丢失部分页的消息。同步刷盘的策略【等待刷盘成功才会返回给producer一个成功的消息】
解释:
同步刷盘:当数据写入到内存中之后立刻刷盘(同步的将内存中的数据持久化到磁盘上),在保证刷盘成功的前提下响应一个消息给Producer。
异步刷盘:数据写入内存后,直接响应一个消息给Producer。异步将内存中的数据持久化到磁盘上。
即使broker设置了同步刷盘,如果主broker磁盘损坏,也是会导致消息丢失。 因此可以给broker指定slave,同时设置master为SYNC_MASTER,然后将slave设置为同步刷盘策略。
此模式下,producer每发送一条消息,都会等消息投递到master和slave都落盘成功了,broker才会当作消息投递成功,从而保证休息不丢失。
在broker端,消息丢失的可能性主要在于刷盘策略和同步机制。
RocketMQ默认broker的刷盘策略为异步刷盘,如果有主从,同步策略也默认的是异步同步,这样子可以提高broker处理消息的效率,但是会有丢失的可能性。因此可以通过同步刷盘策略+同步slave策略(slave也可以进行刷盘)+主从双写的方式解决丢失消息的可能。
从producer投递消息到broker,即使前面这些过程保证了消息正常持久化,但如果consumer消费消息没有消费到也算是消息的丢失。因此RockerMQ默认提供了At least Once机制保证消息可靠消费。
何为At least Once?
Consumer先pull【主动拉取Broker中的信息】 消息到本地,消费完成后,才向服务器返回ack(消费成功的消息--acknowledge)。
通常消费消息的ack机制一般分为两种思路:
1、先提交后消费;
2、先消费,消费成功后再提交【这个更稳当】;
思路一可以解决重复消费的问题但是会丢失消息,因此Rocketmq默认实现的是思路二,由各自consumer业务方保证幂等(通过给每个消息携带一个唯一标识信息,去数据库进行判断。或者在producer的时候就存储一个唯一标识(消息),消费成功删除redis中的消息确保不被重复消费。)来解决重复消费问题。
当消费消息失败了,如果不提供重试消息的能力,则也不能算完全的可靠消费,因此RocketMQ本身提供了重新消费消息的能力。
consumer端要保证消费消息的可靠性,主要通过At least Once+消费重试机制保证。
MQ主要包含了4个组件 nameserver broker producer consumer
然后如何保证消息不丢失又需要对三个消息阶段进行保证
Producer发送消息阶段
1通过采用同步发送消息到broker,等待broker接收到消息过后返回的一个确认消息,虽然效率低,但是时丢失几率最小的方式,异步1和单向消息发送丢失的几率比同步消息丢失的几率大。
2发送消息失败或超时则进行重试。
3broker提供多master模式【即使某台broker宕机了,换一台broker进行投递,保持高可用】
===》采用同步消息和失败重试和多master模式
Broker处理消息阶段
手段四:提供同步刷盘的策略【等待刷盘成功才会返回producer成功】
当数据写入到内存中之后立刻刷盘(同步的将内存中的数据持久化到磁盘上),
手段五:提供主从模式,同时主从支持同步双写
主从broker都同步刷盘成功,才返回producer一个确认消息。
===》采用同步刷盘+broker主从模式,支持同步双写
Consumer消费消息阶段
consumer默认提供的是At least Once机制
手段6 broker队列中的消息消费成功,才返回一个确认消息给broker。
手段7 当消息消费失败了,进行消费消息重试机制(保证幂等就行了。)
===》采用先消费,在返回一个确认消息+消息重试。