什么是 rmq分布式事务消息?
Apache RocketMQ在4.3.0版中已经支持分布式事务消息,这里RocketMQ采用了2PC的思想来实现了提交事务消息,同时增加一个补偿逻辑来处理二阶段超时或者失败的消息,如下图所示。
事务消息解决什么问题?
本地事务与消息发送的原子性问题。
简单解释:本地事务提交,消息肯定发出去;本地事务回滚,消息肯定不能发出去。
目前事务消息现状
chd 基于 rmq 提供的事务消息方案,通过本地事务记录表,简化事务消息开发,封装了上图第6步,提供通用回查的逻辑。
以下单流程为例,简述目前 chd 开发者使用事务消息流程:
以下代码示例当前事务消息开发使用过程:
基于现状,目前使用 rmq 官方提供二阶段事务消息存在以下痛点。
痛点一: 开发理解、使用成本高。
如果不理解 rmq 2pc 事务消息,业务中很难用对、用好。例如忘记很重要的一步 判断事务执行结果
痛点二:rmq事务消息使用时,事务开始前就得构造好业务消息体,但很多情况下只有事务内执行时才能获取到消息体内容
这种场景根本没法使用,或业务代码改造成本很高,例如改造为两个事件并使用中间数据关联。
痛点三:本地事务内发送 rmq 非事务消息,出现本地事务还没提交消息都发出去被错误消费,导致误以为丢消息
如果日志不完善,排查业务问题难度大。这种情况会出现要么被错误消费(事务没提交,查到数据是老的),要么误认为丢消息(消费时回查没数据直接忽略)
其他痛点待整理
因此,分析以上问题,需要提供业务代码侵入低、使用成本低,并能解决以上痛点的本地事务消息表方案
本地事务消息表最终一致性方案
改造思路:
1. 本地存储事务消息内容,和业务流程事务一起成功一起失败
2. 监听事务管理器提交事务的动作,事务提交后再去执行实时发消息
3. 假设事物提交后实时发送消息失败,要有补偿机制确保消息最终能发出去
以下单流程为例,简述实现过程:
开发者使用方式示例
其他内容待整理
SQL备注
ALTER TABLE `xi_local_transaction_log` ADD COLUMN `sendStatus` tinyint UNSIGNED NOT NULL DEFAULT '0' COMMENT '发送状态', ADD COLUMN `payload` text COMMENT '消息载体,json'; ALTER TABLE `order_local_transaction_log` ADD COLUMN `sendStatus` tinyint UNSIGNED NOT NULL DEFAULT '0' COMMENT '发送状态', ADD COLUMN `payload` text COMMENT '消息载体,json'; ALTER TABLE `vaccine_local_transaction_log` ADD COLUMN `sendStatus` tinyint UNSIGNED NOT NULL DEFAULT '0' COMMENT '发送状态', ADD COLUMN `payload` text COMMENT '消息载体,json'; ALTER TABLE `activity_local_transaction_log` ADD COLUMN `sendStatus` tinyint UNSIGNED NOT NULL DEFAULT '0' COMMENT '发送状态', ADD COLUMN `payload` text COMMENT '消息载体,json'; ALTER TABLE `user_local_transaction_log` ADD COLUMN `sendStatus` tinyint UNSIGNED NOT NULL DEFAULT '0' COMMENT '发送状态', ADD COLUMN `payload` text COMMENT '消息载体,json'; ALTER TABLE `commodity_local_transaction_log` ADD COLUMN `sendStatus` tinyint UNSIGNED NOT NULL DEFAULT '0' COMMENT '发送状态', ADD COLUMN `payload` text COMMENT '消息载体,json'; ALTER TABLE `knowledge_local_transaction_log` ADD COLUMN `sendStatus` tinyint UNSIGNED NOT NULL DEFAULT '0' COMMENT '发送状态', ADD COLUMN `payload` text COMMENT '消息载体,json'; ALTER TABLE `credit_local_transaction_log` ADD COLUMN `sendStatus` tinyint UNSIGNED NOT NULL DEFAULT '0' COMMENT '发送状态', ADD COLUMN `payload` text COMMENT '消息载体,json'; ALTER TABLE `distribution_local_transaction_log` ADD COLUMN `sendStatus` tinyint UNSIGNED NOT NULL DEFAULT '0' COMMENT '发送状态', ADD COLUMN `payload` text COMMENT '消息载体,json'; CREATE TABLE `commodity_local_transaction_log` ( `id` bigint(20) unsigned NOT NULL DEFAULT '0' COMMENT '全局id', `createTime` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', `modifyTime` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '修改时间', `transactionId` varchar(32) NOT NULL DEFAULT '' COMMENT '事务ID', `topic` varchar(64) NOT NULL DEFAULT '' COMMENT 'topic名称', `tag` varchar(64) NOT NULL DEFAULT '' COMMENT 'tag名称', `sendStatus` tinyint UNSIGNED NOT NULL DEFAULT '0' COMMENT '发送状态', `payload` text COMMENT '消息载体,json', PRIMARY KEY (`id`), UNIQUE KEY `uniq_transactionId` (`transactionId`) ) DEFAULT CHARSET=utf8mb4 COMMENT='MQ事务消息记录表'; |