RocketMQ源码之事务消息!
RocketMQ源码之事务消息!
月伴飞鱼
Apache RocketMQ在4.3.0版中已经支持分布式事务消息。
RocketMQ采用了2PC的思想来实现了提交事务消息,同时增加一个补偿逻辑来处理二阶段超时或者失败的消息。
基本流程
第一阶段:
- 发送 Message,
Half Message,即半事务消息。- 此类型的
Message是不会被Consumer消费。第二阶段:如果半事务消息投递成功,则会开始执行本地事务。
分为如下三种
Case:
本地事务执行成功:
- 会向
Broker发送commit消息,被commit过后的Message才能被Consumer消费到。本地事务执行失败:
- 会向
Broker发送rollback消息,Broker则会将刚刚投递的半事务消息删除,从而保证上下游数据的一致性。如果
Producer实例或者网络出现了问题,Producer没能及时地将本地事务执行的结果通知Broker。
Broker会通过扫描发现某条Message长时间处于半事务消息状态。
Broker会主动地向Producer询问此Message对应的事务状态。
基本设计
采用2PC两阶段设计:
将
Message原本真实的Topic和MessageQueue进行备份。
- 放入到
PROPERTY_REAL_TOPIC、PROPERTY_REAL_QUEUE_ID中保存。将消息投递到一个内部
Topic中RMQ_SYS_TRANS_HALF_TOPIC,该队列专门存储事务消息。所有的
Half Message全部都写入到queueId为 0 的MessageQueue。因为一个
Topic下只有 1 个MessageQueue:
- 这个
Topic下的所有Message就是全局有序的,它们会按照先来后到的顺序被消费。如果本地事务执行成功进行
Commit,则将RMQ_SYS_TRANS_HALF_TOPIC队列中的消息投递到真实的Topic中,供后续流程执行。
- 并删除这条
Half Message,但删除也是假删除,只是给Message打上一个删除的Tag。如果本地事务执行失败进行
rollback,则直接删除这条Half Message,但删除也是假删除。如果本地事务迟迟没有返回结果 (默认时间是6s),则会触发事务回查机制
- 执行回查之前需要校验检查次数是否到达了最大值(需要手动设置,没有默认值)。
- 或者是当前
Half Message存在是否超过了Message保存的上限,即 3天。- 如果满足上面条件中的一种
Half Message会被放进TRANS_CHECK_MAX_TIME_TOPICTopic 当中。- 一旦判定为需要执行事务回查逻辑,那么当前这条
Half Message就算已经被消费了。- 在没达到最大的校验次数之前,都还需要将其投递到事务队列当中,以便下次重试时再次执行
Check逻辑。- 如果回查成功则删除投递的
Half Message。
















