一、哪些场景会丢失消息
业务场景:下单支付成功后、给用户发送消费券
业务步骤:

用户反馈:支付成功以后,没有收到优惠券。
原因:支付成功的消息丢失了
二、可能丢失消息的环节:
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消息零丢失方案:同步刷盘+主从架构
消费者消息零丢失方案:手动提交+同步消费
学习视频来源:https://www.bilibili.com/video/BV1BB4y1H7VW?share_source=copy_web