共计 4197 个字符,预计需要花费 11 分钟才能阅读完成。
作者:合伯
引言:在分布式系统调用场景中存在这样一个通用问题,即在执行一个外围业务逻辑的同时,还须要调用多个上游做业务解决,而且要求多个上游业务和以后外围业务必须同时胜利或者同时失败,进而防止局部胜利和失败的不统一状况呈现。简略来说,音讯队列中的“事务”,次要解决的是音讯生产者和消费者的数据一致性问题。本篇文章通过拆解 RocketMQ 事务音讯的应用场景、基本原理、实现细节和实战应用,帮忙大家更好的了解和应用 RocketMQ 的事务音讯。
点击下方链接,查看视频解说:
https://yqh.aliyun.com/live/d…
场景:为什么须要事务音讯
以电商交易场景为例,用户领取订单这一外围操作的同时会波及到上游物流发货、积分变更、购物车状态清空等多个子系统的变更。以后业务的解决分支包含:
- 主分支订单零碎状态更新:由未领取变更为领取胜利;
- 物流零碎状态新增:新增待发货物流记录,创立订单物流记录;
- 积分零碎状态变更:变更用户积分,更新用户积分表;
- 购物车零碎状态变更:清空购物车,更新用户购物车记录。
分布式系统调用的特点是:一个外围业务逻辑的执行,同时须要调用多个上游业务进行解决。因而,如何保障外围业务和多个上游业务的执行后果完全一致,是分布式事务须要解决的次要问题。
传统 XA 事务计划:性能有余
为了保障上述四个分支的执行后果一致性,典型计划是基于 XA 协定的分布式事务零碎来实现。将四个调用分支封装成蕴含四个独立事务分支的大事务,基于 XA 分布式事务的计划能够满足业务处理结果的正确性,但最大的毛病是多分支环境下资源锁定范畴大,并发度低,随着上游分支的减少,零碎性能会越来越差。
基于一般音讯计划:一致性保障艰难
将上述基于 XA 事务的计划进行简化,将订单零碎变更作为本地事务,剩下的零碎变更作为一般音讯的上游来执行,事务分支简化成一般音讯 + 订单表事务,充分利用音讯异步化的能力缩短链路,进步并发度。
该计划中音讯上游分支和订单零碎变更的主分支很容易呈现不统一的景象,例如:
- 音讯发送胜利,订单没有执行胜利,须要回滚整个事务;
- 订单执行胜利,音讯没有发送胜利,须要额定弥补能力发现不统一;
- 音讯发送超时未知,此时无奈判断须要回滚订单还是提交订单变更。
基于 RocketMQ 分布式事务音讯:反对最终一致性
上述一般音讯计划中,一般音讯和订单事务无奈保障统一的实质起因是一般音讯无奈像单机数据库事务一样,具备提交、回滚和对立协调的能力。
而基于音讯队列 RocketMQ 版实现的分布式事务音讯性能,在一般音讯根底上,反对二阶段的提交能力。将二阶段提交和本地事务绑定,实现全局提交后果的一致性。
音讯队列 RocketMQ 版事务音讯的计划,具备 高性能、可扩大、业务开发简略 的劣势。
基本原理
概念介绍
- 事务音讯:RocketMQ 提供相似 XA 或 Open XA 的分布式事务性能,通过 RocketMQ 事务音讯能达到分布式事务的最终统一;
- 半事务音讯:暂不能投递的音讯,生产者曾经胜利地将音讯发送到了 RocketMQ 服务端,然而 RocketMQ 服务端未收到生产者对该音讯的二次确认,此时该音讯被标记成“暂不能投递”状态,处于该种状态下的音讯即半事务音讯;
- 音讯回查:因为网络闪断、生产者利用重启等起因,导致某条事务音讯的二次确认失落,RocketMQ 服务端通过扫描发现某条音讯长期处于“半事务音讯”时,须要被动向音讯生产者询问该音讯的最终状态(Commit 或是 Rollback),该询问过程即音讯回查。
事务音讯生命周期
- 初始化:半事务音讯被生产者构建并实现初始化,待发送到服务端的状态;
- 事务待提交:半事务音讯被发送到服务端,和一般音讯不同,并不会间接被服务端长久化,而是会被独自存储到事务存储系统中,期待第二阶段本地事务返回执行后果后再提交。此时音讯对上游消费者不可见;
- 音讯回滚:第二阶段如果事务执行后果明确为回滚,服务端会将半事务音讯回滚,该事务音讯流程终止;
- 提交待生产:第二阶段如果事务执行后果明确为提交,服务端会将半事务音讯从新存储到一般存储系统中,此时音讯对上游消费者可见,期待被消费者获取并生产;
- 生产中:音讯被消费者获取,并依照消费者本地的业务逻辑进行解决的过程。此时服务端会期待消费者实现生产并提交生产后果,如果肯定工夫后没有收到消费者的响应,RocketMQ 会对音讯进行重试解决。具体信息,请参见音讯重试;
- 生产提交:消费者实现生产解决,并向服务端提交生产后果,服务端标记以后音讯曾经被解决(包含生产胜利和失败);RocketMQ 默认反对保留所有音讯,此时音讯数据并不会立刻被删除,只是逻辑标记已生产。音讯在保留工夫到期或存储空间有余被删除前,消费者依然能够回溯音讯从新生产。
- 音讯删除:当音讯存储时长到期或存储空间有余时,RocketMQ 会依照滚动机制清理最早保留的音讯数据,将音讯从物理文件中删除。
事务音讯根本流程
事务音讯交互流程如下图所示:
- 生产者将音讯发送至 RocketMQ 服务端;
- RocketMQ 服务端将音讯长久化胜利之后,向生产者返回 Ack 确认音讯曾经发送胜利,此时音讯被标记为“暂不能投递”,这种状态下的音讯即为半事务音讯;
- 生产者开始执行本地事务逻辑;
- 生产者依据本地事务执行后果向服务端提交二次确认后果(Commit 或是 Rollback),服务端收到确认后果后处理逻辑如下:
- 二次确认后果为 Commit:服务端将半事务音讯标记为可投递,并投递给消费者;
- 二次确认后果为 Rollback:服务端将回滚事务,不会将半事务音讯投递给消费者。
- 在断网或者是生产者利用重启的非凡状况下,若服务端未收到发送者提交的二次确认后果,或服务端收到的二次确认后果为 Unknown 未知状态,通过固定工夫后,服务端将对音讯生产者即生产者集群中任一生产者实例发动音讯回查;
- 生产者收到音讯回查后,须要查看对应音讯的本地事务执行的最终后果;
- 生产者依据查看到的本地事务的最终状态再次提交二次确认,服务端仍依照步骤 4 对半事务音讯进行解决。
实现细节:RocketMQ 事务音讯如何实现
依据发送事务音讯的根本流程的须要,实现分为三个次要流程:接管解决 Half 音讯、Commit 或 Rollback 命令解决、事务音讯 check。
解决 Half 音讯
发送方第一阶段发送 Half 音讯到 Broker 后,Broker 解决 Half 音讯。Broker 流程参考下图:
具体流程是首先把音讯转换 Topic 为 RMQ_SYS_TRANS_HALF_TOPIC,其余音讯内容不变,写入 Half 队列。具体实现参考 SendMessageProcessor 的逻辑解决。
Commit 或 Rollback 命令解决
发送方实现本地事务后,持续发送 Commit 或 Rollback 到 Broker。因为以后事务曾经完结,Broker 须要删除原有的 Half 音讯,因为 RocketMQ 的 appendOnly 个性,Broker 通过 OP 音讯实现标记删除。Broker 流程参考下图:
- Commit。Broker 写入 OP 音讯,OP 音讯的 body 指定 Commit 音讯的 queueOffset,标记之前 Half 音讯已被删除;同时,Broker 读取原 Half 音讯,把 Topic 还原,从新写入 CommitLog,消费者则能够拉取生产;
- Rollback。Broker 同样写入 OP 音讯,流程和 Commit 一样。但后续不会读取和还原 Half 音讯。这样消费者就不会生产到该音讯。
具体实现在 EndTransactionProcessor 中。
事务音讯 check
如果发送端事务工夫执行过程,发送 UNKNOWN 命令,或者 Broker/ 发送端重启公布等起因,流程 2 的标记删除的 OP 音讯可能会缺失,因而减少了事务音讯 check 流程,该流程是在异步线程定期执行(transactionCheckInterval 默认 30s 距离),针对这些缺失 OP 音讯的 Half 音讯进行 check 状态。具体参考下图:
事务音讯 check 流程扫描以后的 OP 音讯队列,读取曾经被标记删除的 Half 音讯的 queueOffset。如果发现某个 Half 音讯没有 OP 音讯对应标记,并且曾经超时(transactionTimeOut 默认 6 秒),则读取该 Half 音讯从新写入 half 队列,并且发送 check 命令到原发送方查看事务状态;如果没有超时,则会期待后读取 OP 音讯队列,获取新的 OP 音讯。
另外,为了防止发送方的异样导致长期无奈确定事务状态,如果某个 Half 音讯的 bornTime 超过最大保留工夫(transactionCheckMaxTimeInMs 默认 12 小时),则会主动跳过此音讯,不再 check。
具体实现参考:
TransactionalMessageServiceImpl#check 办法。
实战:应用事务音讯
理解了 RocketMQ 事务音讯的原理后,咱们看下如何应用事务。首先,咱们须要创立一个“事务音讯”类型的 Topic,能够应用控制台或者 CLi 命令创立。
事务音讯相比一般音讯发送时须要批改以下几点:
- 发送事务音讯前,须要开启事务并关联本地的事务执行。
- 为保障事务一致性,在构建生产者时,必须设置事务查看器和预绑定事务音讯发送的主题列表,客户端内置的事务查看器会对绑定的事务主题做异样状态复原。
当事务音讯 commit 之后,这条音讯其实就是一条投递到用户 Topic 的一般音讯而已。所以对于消费者来说,和一般音讯的生产没有区别。
留神:
- 防止大量未决事务导致超时:在事务提交阶段异样的状况下发动事务回查,保障事务一致性;但生产者应该尽量避免本地事务返回未知后果;大量的事务查看会导致系统性能受损,容易导致事务处理提早;
- 事务音讯的 Group ID 不能与其余类型音讯的 Group ID 共用: 与其余类型的音讯不同,事务音讯有回查机制,回查时服务端会依据 Group ID 去查问生产者客户端;
- 事务超时机制:半事务音讯被生产者发送服务端后,如果在指定工夫内服务端无奈确认提交或者回滚状态,则音讯默认会被回滚。
明天通过对 RocketMQ 事务音讯的介绍,心愿可能帮大家对事务音讯的原理和利用有更深刻的理解,同时也冀望 RocketMQ 的事务音讯可能帮忙您更无效的解决业务问题。如果您对 RocktMQ 的业务音讯感兴趣,也欢迎您扫描下方二维码退出钉钉群一起沟通交流~
点击此处,进入官网理解更多详情~