rocketmq——通过学习后对于rocketmq分布式事务的理解

在搜了三天资料后,对于rocketmq的事务消息特性有了一定的了解,现在就分享一下我在看了下面几篇文章之后对于rocketmq实现分布式事务的理解。

参考文章:

对于rocketmq事务消息特性的理解

还是以“Bob给Smith转100块”为例。

通过把一整个大的事务拆成两个小事务异步执行来提高系统的吞吐量,这里的拆分指的是,事务一:Bob扣100;事务二:Smith加100;事务一成功后发送异步消息给事务二,从而事务一和事务二异步执行,但我们需要保证Bob-100后,发送消息必须成功,怎么保证呢?有一种方式是我们可以将扣款和发送消息放到同一个本地事务中或者通过别的实现方式,只要保证要么他俩都成功,要么都不成功的效果即可;还有一种方式就是通过RocketMQ的事务消息特性实现,它能够确保解决本地事务执行与消息发送的原子性

整体流程如下(这里使用Rocketmq的事务消息特性实现):

  1. rocketmq先发送一条prepared消息给broker并返回消息地址,有两种发送结果

    1. 发送失败,则返回事务状态设为UNKNOW(未知)
    2. 发送成功直接进入2

    注1:参考文章摘抄如下:

    由于该类型的消息在保存的时候,commitLogOffset没有被保存到consumerQueue中,此时客户端通过consumerQueue取不到commitLogOffset,所以该类型的消息无法被取到,导致不会被消费。

  2. rocketmq调用事务处理逻辑(Bob扣100),有一下几种结果的:

    1. 处理成功,返回本地事务状态为COMMIT(提交)

    2. 处理失败,返回本地事务状态为ROLLBACK(回滚)

    3. 处理结果未知,返回本地事务状态为UNKNOW

  3. producer将请求发往mq去更新事务消息的最终状态

  4. broker收到请求后判断消息类型,有NOT事务消息,有COMMIT事务消息,有ROLLBACK事务消息

    1. 如果是COMMIT,则将该条消息转发给对应的消费者(实际上“会被转发到原消息主题对应的消费队列,被消费者消费。”),并删除预处理消息(prepare),其实是将消息存储在主题为:RMQ_SYS_TRANS_OP_HALF_TOPIC的主题(Operation Topic)中,代表这些消息已经被处理(提交或回滚)。 进入8
    2. 如果是ROLLBACK,会将消息存储在RMQ_SYS_TRANS_OP_HALF_TOPIC(Operation Topic)中,代表该消息已被处理。

    **注0:**Half Topic存放的是prepared消息,Operation Topic存放的是prepared消息对应的commit/rollback消息,消息体中存放的则是prepared message对应的offset,服务端通过比对两个队列的差值来找到尚未提交的超时事务,进行回查。

    注1:其核心实现就是根据commitlogOffset找到消息,如果是提交动作,就恢复原消息的主题与队列,再次存入commitlog文件进而转到消息消费队列,供消费者消费,然后将原预处理消息存入一个新的主题RMQ_SYS_TRANS_OP_HALF_TOPIC,代表该消息已被处理;回滚事务只是把原预处理消息存入新主题RMQ_SYS_TRANS_OP_HALF_TOPIC内,代表该消息已被处理。提交与回滚事务消息不同的是,提交事务消息会将消息恢复原主题与队列,再次存储在commitlog文件中(以便让消费者消费,而ROLLBACK则不会被投递给消费者)。

    注2:如果有消息长期处于PREPARED状态,则需要一种补偿机制。rocketmq的实现方式是:会有一个定时任务,实现事务消息定时回查,rocketmq目前有两种实现方式,基于文件系统和基于数据库的。

    ​ 具体流程:broker会定时扫描PREPARED状态的消息,如果该消息达到了最小轮询时间,就会向生产者发送checkTransactionState请求,生产者会调用用户自定义的TransactionListener.checkLocalTransaction()方法,对本地事务状态进行检查。

  5. 消费者收到消息(代表Smith所在的机器的消费者收到+100块的消息),手动实现本地事务逻辑,这时候失败的话,有两种结果:消费超时和业务逻辑失败,分别这么做:

    • 消费超时:MQ会帮你一直重试,直至成功(这时候可能出现重复消费,需要保证消费的幂等性)。
    • 业务逻辑失败:这时候,需要人工手动实现整个流程的回滚,具体摘抄如下:

    所以针对消费失败这种情况,最好的办法就是通过报警系统及时发现失败情况然后再人工处理。其实为了交易系统更可靠,我们一般会在类似交易这种高级别的服务代码中,加入详细日志记录的,一旦系统内部引发类似致命异常要及时通过短信、邮件通知给业务方。同时,应该设计一个报警系统在后台实时扫描和分析此类日志,检查出这种特殊的情况,通过短信、邮件及时通知相关人员。

  6. 附rocketmq事务消息的实现逻辑图,在这里我们会看到如果Half消息的最终状态为ROLLBACK的话,会被discard,而不会被消费者消费:

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值