基于ActiveMQ的分布式事务

目前常见的解决分布式事务问题的方案有:两阶段提交(2PC)、补偿事务(TCC)、本地事件表加消息队列、MQ事务消息等。

以用户注册场景为例,需求是新用户注册之后给该用户新增一条积分记录。假设有用户和积分两个服务,用户服务使用数据库DB1,积分服务使用数据库DB2。服务调用者只需使用新增用户服务,由该服务内部既在DB1新增了用户记录,又在DB2新增了积分记录。显然这是一个分布式事务问题。下面看看如何使用本地事务表加消息队列实现这个需求。

问题的核心是DB1中的事务完成后,需要协调通知DB2执行事务,这可以通过消息队列来实现。在用户服务成功保存用户记录后向消息队列的某个主题发送一条用户创建消息,积分系统需要监听该主题,一旦收到了用户创建的消息,积分系统就在DB2中为该用户创建一条积分记录。

具体步骤如下:

  1. 用户服务接收到请求后在t_user表中创建一条用户记录,并在t_event表中新增一条process为NEW的事件记录,同时要创建的积分数据以JSON字符串的形式保存到t_event表的content中,提交事务。
  2. 在用户系统中开启一个定时任务定时查询t_event表中所有process为NEW的记录,一旦有记录则向消息队列(这里使用ActiveMQ)发送消息,消息的内容就是t_event表的content,消息发送成功后把process改为PUBLISHED,提交事务。
  3. 积分系统接收到消息后在DB2的t_event表中新增一条process为PUBLISHED的记录,content保存接收到的消息内容,保存t_event成功后返回,提交事务。
  4. 在积分系统中开启一个定时任务定时查询t_event表中所有process为PUBLISHED的记录,拿到表记录后将其content字段的内容转换成积分对象,保存积分记录,保存成功后修改t_event的process为PROCESSED,提交事务。

基于ActiveMQ的分布式事务

代码下载地址:http://www.broadview.com.cn/book/5691

这种事件表加消息队列的方式实际上是将事务变成了异步执行,而与2PC这种同步事务处理相比,该方案的优点是:

  • 吞吐量达,因为不需要等待其他数据源响应。
  • 容错性好,比如A服务在发布事件时B服务甚至可以不在线。

缺点也很明显,为了协调两个系统数据的一致,会出现很多中间状态,并且编程也比较复杂。总的来说,最终一致性方案恰恰是比较适合实际业务场景的分布式事务思路的解决思路,但具体实现并不止一种,比如市面上有的消息队列产品支持事务的特性(如RocketMQ),这就衍生出另一种思路。