摘要
分布式系统之前除了同步方式通过RPC框架调用接口,还有很多通讯是异步的方式通过MQ中间件完成的。本文主要介绍后者实现分布式事务的一种方案,核心思想是通过记录本地消息日志表的方式,借助本地事务和MQ消息中间件的可靠性来实现分布式系统中多个节点间状态的最终一致。
方案设计
消息发布方
发布方的数据库中增加消息日志表,将业务操作和插入消息日志放在同一个数据库事务中。通过后台线程的定时任务不断从消息日志表中读取消息,并投递到MQ中间件。
消息订阅方
为了防止重复消费,订阅方数据库需要增加消息接收表来记录已消费的消息。将业务操和插入消息接收记录放在同一个数据库事务中。事务成功则调用发布方的回调,更新发布方消息日志表中的消息状态。
业务场景
现在有电话营销系统(后面简称电销系统)和调度平台两个系统。电销系统处理具体电销案件作业逻辑,依赖于调度平台将案件分配给人处理。电销系统中有marketing_task表维护电销案件,调度平台有dispatching_task表维护包括电销系统、催收系统、审批系统等业务系统在内的多种业务案件。
电销系统生成电销案件后,是通过MQ中间件将案件信息推送调度平台,后者异步将案件保存并完成后续分配。
下面我们就来看下如何通过本地消息表方案来保证电销系统和调度平台之间,案件状态的最终一致。
方案实践
通过上面描述,很明显电销系统是消息生产方。在电销数据库中业务表marketing_task对应的bean是Task,我们创建再一个本地消息表trans_message,对应bean是TransMessage。下面代码中我们定义一个推送电销任务(案件)的本地事务:将电销案件表中指定ID的案件状态更新为“处理中”,同时记录一条消息日志,将本地事务ID,电销案件ID,消息状态插入trans_message表。
[spring+mybatis]
@Transactional
public void pushTask(String caseNo){