⼀、哪些场景会丢失消
业务场景:下单⽀付成功后、给⽤户发送消费
⽤户反馈:⽀付成功以后,没有收到优惠券。原因:⽀付成功的消息丢失了
⼆、可能丢失消息的环节:
1、订单系统(⽣产者)向MQ推送消息的过程中丢失
可能原因:1、发送MQ的过程中⽹络波动;2、MQ确实收到消息了,但MQ的⽹络通信出现问题导致消息⽆法完成处理;3、在发送消息给MQ的过程中,MQ主节点故障,恰好在主从切换;4、其他等等原因
2、消息已经发送到MQ,MQ⾃身导致消息的丢失
可能原因:rocketMQ真正写⼊成功是指消息写⼊到了PageCache中,如果在这个过程中服务宕机就会导致消息写⼊失败
3、MQ已经写⼊到磁盘,但磁盘损坏导致消息的丢失
4、消息已经发送到优惠券系统(消费者)
可能原因:消费者已经接受消息,并完成了ACK,但这时候消费者在发优惠券前宕机了,也会导致丢失
三、⽣产者消息零丢失⽅案
问题:订单已经变更⽀付状态,但是消息却没有发送到MQ
解决⽅案:
1、发送消息,但消息状态是Half,判断⽹络是否正常;如果成功发送,更新订单为已⽀付,如果失败,就退款。
2、检查本地事务是否成功,如果订单状态更新成功,就向MQ发送commit,本地事务提交;如果失败就
rollback,本地事务也跟着回滚。
MQ接受到commit后会把之间的half消息进⾏提交,提交后,消息就对优惠券系统(消费者)可⻅,此时优惠券系
统就可以消费消息。
如果在订单更新状态后发送commit失败,这时候会有⼀个定时器,处理⻓时间未提交或回滚的half消息,会回查订单系统的事务状态。
回查事务状态:如果事务时已提交,那么订单系统就发送commit,如果是已回滚,那么久发送rollback。
补偿机制:
这个机制确保了订单发送消息给MQ的过程的⼀个⼀致性。
总结:事务消息机制或重试机制
四、事务消息机制的底层原理
问题:half消息是如何对消费者不可⻅的?
如果这时候消息回滚,half消息并不会物理删除,⽽是逻辑删除
如果没有收到commit/rollback,则会触发MQ的补偿机制
1、定时任务扫描RMQ_SYS_TRANS_HALF_TOPIC中⻓时间没有提交/回滚的消息,回查⽣产者业务的本地事务状
态。
2、最多重试15次,超过15次,⾃动rollback。
事务消息流程机制
除了事务消息,是否还有其他⽅法可以保证消息零丢失?
1、同步发送+重试:把消息发送也放在本地事务中,这时候修改订单操作+发送消息要么都执⾏、要么都不执⾏。
缺点:这个发送消息可能会因为⽹络堵塞⽽不断重试导致耗时过⻓,⽀付超时
五、Broker消息零丢失⽅案
问题:消息还在PageCache,还没刷盘到磁盘,如果此时服务宕机,数据就会丢失。
解决⽅案:
MQ有2种刷盘机制:异步刷盘和同步刷盘。
异步刷盘:只把数据刷到PageCache,吞吐量和性能⾼,但容易丢失数据
同步刷盘:把数据刷到磁盘中才算完成,性能低,但安全
因此,在这⾥我们可以采⽤同步刷盘的策略来避免消息的丢失。
问题:这时候磁盘坏了呢?
这时候即使同步刷盘,数据还是会丢失。
解决⽅案:主从同步避免单机的磁盘损坏⻛险。
总结:要保证不丢失,要同步刷盘+主从同步
六、消费者消息零丢失⽅案
问题:消费者在拿到消息以后,还没来的及处理,就提交offset给broker,但这时,消费者服务器挂了。
解决⽅案:把⾃动提交改为⼿动提交的⽅式。
问题:现在已经⼿动提交了,但是却开启了⼦线程异步消费消息,这时候⼦线程消费完消息⼿动提交,但是主线程
的业务还没⾛完,然后⼜宕机了,这时候重启后因为offset已经被⼦线程提交了,所以消费者就不会再去拉去消息
了。
总结:要保证不丢失,需要改成⼿动提交+同步消费。
最后,总结:
⽣产者消息零丢失⽅案:事务消息或重试机制
broker消息零丢失⽅案:同步刷盘+主从架构
消费者消息零丢失⽅案:⼿动提交+同步消费