前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >探秘RocketMQ事务机制,如何保证消息零丢失

探秘RocketMQ事务机制,如何保证消息零丢失

作者头像
慕枫技术笔记
发布2023-03-20 11:25:28
1K0
发布2023-03-20 11:25:28
举报
文章被收录于专栏:慕枫技术笔记慕枫技术笔记

事务的概念就不用多说了,我相信阅读文章的童鞋都是有着非常深刻的认识。我们都知道MQ可以实现微服务之间的异步以及解耦,那么引入MQ之后,如何实现微服务之间的数据一致性是一个值得思考的问题。RocketMQ事务消息正是解决这个问题的解决方案。另外事务消息也是为了解决消息丢失问题。


哪些场景会出现消息丢失

在分析RocketMQ事务消息之前,我们先来分析下引入消息中间件之后,整个消息链路在哪些场景会出现消息丢失的异常情况。

当我们支付订单之后,我们账户的购物积分也会进行相应的积分调整。我们结合下面的订单服务、RocketMQ、积分服务的简化交互图来看,我们来分析下整个链路中可能会出现的消息丢失问题。

场景1:在订单服务向RocketMQ发送订单成功生成的消息的时候,可能由于网络抖动的问题导致订单消息没能正常投递到RocketMQ,导致消息丢失。

场景2:那么假如订单服务以及RocketMQ之间的网络没问题,消息正常被RocketMQ接收到了,那么会存在消息丢失的情况吗?答案是肯定的,这和RocketMQ的持久化机制有关系,当消息到达RocketMQ之后,并不是立马落盘存储,而是存储在page cache中的。如果此时出现服务器断电或者宕机情况,那么还没来得及落盘的消息数据就有可能丢失。另外即使是落到磁盘当中,如果出现磁盘坏道的话,依然会出现消息数据的可能。

场景3:如果前面两种场景都没问题,积分服务拿到订单消息了。还会出现消息丢失的问题吗?答案依然是肯定的。即便是积分服务拿到了订单消息,当积分服务自动提交消息offset到RocketMQ中,但是此时如果出现宕机或者积分服务挂了,没有将本该增加的积分进行处理,此时也就出现了消息丢失的情况。

事务消息机制原理

half消息

所谓的RocketMQ事务机制,其实是RocketMQ提供了一种half消息的机制。当订单服务接受到订单支付信息后,订单服务会发送half消息到RocketMQ中,这个half消息是不被消费者所见的。怎么理解这个half信息呢,按照我自己的理解,就是它实现了一半的消息功能,只在生产端可见,在消费端不可见。另外这个half信息相当于一种RocketMQ的可用性探测,如果half消息都发送失败的话,就不必再进行下游业务的一系列操作了。

如果此时用于探测RocketMQ的可用性的half消息发送失败了,那么说明此时订单服务与RocketMQ存在异常,则会对之前订单进行一系列的回滚操作。如果half消息被成功投递,则需要进行本地事务操作,更新订单状态。

如果本地事务执行失败了怎么办,订单服务可以发送rollback请求,将之前的half消息从RocketMQ中进行删除,不再进行后续的消息投递。

half消息原理分析

上文提到half消息不被消费端可见,那么这个half消息是怎么实现在RocketMQ中不被积分服务所见的呢?

订单服务发送half消息,实际并不是将消息投递到积分服务订阅的topic,而是将消息投递到RocketMQ中的RMQ_SYS_TRANS_HALF_TOPIC对应的messeageQueue。由于积分服务并没有订阅这个Topic,所以这个消息对于积分服务是不可见的。

另外有个OP_TOPIC用于记录对应half消息的commit/rollback状态。大致的交互如下如所示:

如果订单服务half消息发送失败了,由于网络原因或者RocketMQ挂了,那么此时需要执行一些回滚操作,让订单进行关闭。因为订单信息无法通知到下游服务了。

那么如果half消息已经写入RocketMQ中,但是本地事务执行失败又该怎么办呢?也就是说当订单服务接收到half消息写入成功的响应后,更新订单信息时发生了异常,无法完成状态更新。那么此时订单服务需要发送rollback的请求给RocketMQ,通知其将原来的half信息进行删除。如果本地事务执行成功,则需要发送commit请求给RocketMQ,RocketMQ会将原先存在RMQ_SYS_TRANS_HALF_TOPIC中的消息重新投递到积分服务订阅的TOPIC中去,这样积分服务就可以正常消费信息进行下一步的积分操作了。

再考虑一种情况,如果订单服务发送commit或者rollback请求未正常投递到RocketMQ中,RocketMQ不知道half消息到底是对应的本地事务到底是执行成功了还是执行失败了。针对这种情况,订单服务需要提供状态回查接口,RocketMQ定时检测是否还有没有处理的half消息,当存在这样的消息时,RocketMQ调用回查接口确认本地事务执行情况。执行失败的则删除half消息,执行成功则重新投递消息。

重新投递消息到对应的ConsumerQueue中,而此时积分服务订阅了对应的订单topic,可以正常消费这个消息了,继续后续的业务流程。

总结

通过上文的分析,订单服务和RocketMQ之间的交互,通过事务消息机制可以保证消息可以被可靠投递。至少在订单服务和RocketMQ之间不会出现消息丢失的问题。

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2021-05-23,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 慕枫技术笔记 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
相关产品与服务
消息队列 TDMQ
消息队列 TDMQ (Tencent Distributed Message Queue)是腾讯基于 Apache Pulsar 自研的一个云原生消息中间件系列,其中包含兼容Pulsar、RabbitMQ、RocketMQ 等协议的消息队列子产品,得益于其底层计算与存储分离的架构,TDMQ 具备良好的弹性伸缩以及故障恢复能力。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档