消息中间件如何保证消息可靠性

Kafka

producer端

ack机制

ack=0 发送端不感应broker是否接收成功

ack=1 消息发送到leader broker上,就认为消息发送成功了;但是消息还在page cache的时候,其他follow副本还没拉取消息之前,leader broker就断电了,消息也会丢失

ack=-1 消息发送到leader broker,并且成功写入所有isr的follow 副本才会认为消息发送成功,可靠性最高

控制消息生产速率,防止发送线程跟不上生产线程,buffer打满,导致OOM,比如使用阻塞队列方式来减缓

消息生产时进行持久化到DB或者本地,消息发送成功进行callback删除

broker端

通过调节磁盘刷盘机制降低消息丢失概率,同步刷盘/异步刷盘频率提高,减少刷盘量

通过多副本机制来保证

consumer端

消费端关闭自动提交改为手动提交,消息成功消费后手动提交offset

RabbitMQ

exchange和queue之间存在正确的绑定关系
producer端,保证消息可以发送到queue,前提是exchange和queue之间有映射关系

事务模式,一条消息发送之后会使发送端阻塞,性能太差

callback confirm模式,一旦发布一条消息,生产者就可以继续发送下一条消息,当消息最终得到确认之后,生产者应用便可以通过回调方法来处理该确认消息,如果RabbitMQ因为自身内部错误导致消息丢失,就会发送一条nack(Basic.Nack)命令,生产者应用程序同样可以在回调方法中处理该nack命令 ;再补充一个Mandatory参数:当Mandatory参数设为true时,如果目的不可达,会发送消息给生产者,生产者通过一个回调函数来获取该信息。

queue

queue和消息都要做持久化操作,只持久化queue,queue内部的消息会丢;只持久化queue,服务重启后queue丢失,消息也无处存放。持久化消息并不是同步刷盘,也是异步刷盘,上面说的事务和confirm都是消息落到磁盘后才会执行,但是无法保证单机故障无法恢复的情况

镜像队列,镜像队列相当于配置了副本,绝大多数分布式的东西都有多副本的概念来确保HA。在镜像队列中,如果主节点(master)在此特殊时间内挂掉,可以自动切换到从节点(slave),这样有效的保证了高可用性,除非整个集群都挂掉

消费端

关闭自动ack,autoAck=true的情况下队列将消息投递给消费者后,就将消息标记为删除,如果消费者没有正确消费就宕机,消息丢失

手动进行消息ack,消息消费失败通过reject来拒绝消息不要直接确认,消息reject,requeue=false的情况下消息不会放回原来的队列,而是转发到指定的死信队列,可以对死信进行特殊处理

RocketMQ

producer

默认情况下,可以通过同步的方式阻塞式的发送,check SendStatus,状态是OK,表示消息一定成功的投递到了Broker,状态超时或者失败,则会触发默认的2次重试。此方法的发送结果,可能Broker存储成功了,也可能没成功

采取事务消息的投递方式,并不能保证消息100%投递成功到了Broker,但是如果消息发送Ack失败的话,此消息会存储在CommitLog当中,但是对ConsumerQueue是不可见的。可以在日志中查看到这条异常的消息,严格意义上来讲,也并没有完全丢失

RocketMQ支持 日志的索引,如果一条消息发送之后超时,也可以通过查询日志的API,来check是否在Broker存储成功

broker

消息持久化到日志文件

支持同步刷盘和异步刷盘

采用一主多从的复制模式,支持同步复制和异步复制

consumer

手动提交offset

并行消费时提交的时message queue中最小的offset

consumer的offset定时持久化,可配置

集群模式,定时持久化到remote name server

广播模式,offset定时持久化到local file,不涉及到reblance,不涉及消息重新投递回broker

消息可靠性的套路

  1. 消息提前持久化DB

  2. producer+confirm机制,消息发送成功将第一步保存的消息删除;消息发送失败,通过定时任务重新发送

  3. broker端,消息配置持久化,通常都是异步刷盘,可以通过调节刷盘机制(可靠性和性能之间的权衡);通常配备多副本机制来保证单店故障问题

  4. 消费端不要采用中间件的自动提交,交给使用方来做手动提交

参考文档

https://juejin.im/entry/5bbc22135188255c6a0456ef

https://www.jianshu.com/p/3213d8c29fd0

你可能感兴趣的:(消息中间件如何保证消息可靠性)