分布式事务之事务消息

为什么需要事务消息?

用一个经典的场景来举个例子:在电商行业中,用户下订单后,是需要和其他服务联动来完成后续的操作的,例如:

  1. 订单服务:创建订单
  2. 库存服务:扣减库存
  3. 支付服务:商品付款
  4. 积分服务:增加积分
  5. 物流服务:创建物流单(待发货)

这些服务的操作都需要满足原子性,要么全部成功,要么全部失败。为了业务的高性能,我们会选择异步消息通知的方式去实现分布式事务。

方案一:先提交本地事务,再发送消息通知下游服务

如果我们在成功创建订单后提交了本地事务,然后再通过消息通知的方式去通知库存服务区扣减库存,订单服务的操作流程如下:

  1. 开启事务
  2. 创建订单
  3. 提交事务
  4. 发送消息到消息队列

这时候,如果本地事务提交成功,但是消息发送的时候,发送失败了,并且没有其他补救措施,这就会导致商品的库存没有扣减,产生了数据不一致的问题。对于这个,我们可能会想到方案二。

方案二:先发送消息,再开启本地事务并提交

流程如下:

  1. 发送消息到消息队列
  2. 开启事务
  3. 创建订单
  4. 提交事务

在发送消息成功后,才开启本地事务,如果消息发送失败,则不开启本地事务。

这个方案也有弊端:如果消息发送成功,下游服务已经消费了消息了,但是本地事务执行失败,这就不能及时地阻断分布式事务的流程,导致可能发生库存已经扣减,但是订单还没有创建的问题。那如果把消息发送包在本地事务里面呢?

方案三:在创建完订单后,在本地事务中去发送消息通知

流程如下:

  1. 开启事务
  2. 创建订单
  3. 发送消息到消息队列
  4. 提交事务

这样,如果消息发送失败了,可以回滚本地事务。

但是,如果我们在事务中对第三方服务进行的io操作,这可能会导致当前服务的资源锁定时间过长而导致性能问题,影响其他业务对同一资源的访问。

还有一个问题是,如果我们消息已经发送出去了,但是提交事务失败了,这时本地事务是可以回滚的,但是消息发出去了就不能回滚了。

所以这个方案也是不推荐使用的。

那么还有其他的方案吗?这时就需要使用事务消息的方式来进行消息投递了。

事务消息的原理

在 RocketMQ 中有一种事务消息,它能通过两阶段提交的方式来保证本地事务和消息投递操作的原子性。 事务消息的交互流程如下:

以订单服务为例:

  1. 订单服务在执行下订单操作之前,先发送半事务消息到 RocketMQ 服务端;
  2. RocketMQ 服务返回半事务消息发送成功;
  3. 接着订单服务开始执行本地事务,并提交本地事务;
  4. 如果订单服务的本地事务提交失败,则发送 Rollback 消息到 RocketMQ 服务端,服务端就不会把消息投递到下游服务;如果订单服务的本地事务提交成功,则发送 Commit 消息到 RocketMQ 服务端,服务端这时才会把消息投递到下游服务器,下游服务消费到消息就会执行对应的事务操作;
  5. 如果 RocketMQ 迟迟没有接收到订单服务发来的 Commit 或 Rollback 消息,则会主动回查事务的状态(订单服务需要提供对应的回查接口),订单服务则会检查本地事务的状态,然后再根据事务的状态返回 Commit 或 Rollback 消息。

通过RocketMQ事务消息的两阶段投递的方式,以及RocketMQ回查事务状态来兜底,从而保证了「本地事务+下游服务的消息投递」是原子性的,能够保证最终的一致性,并且也不会影响当前服务的性能。

事务消息的局限?

RocketMQ 事务消息本身只能保证消息的可靠投递,它可以让消息投递进行回滚,从而阻止下游服务继续执行事务,但是当下游服务消费失败时,则需要额外机制保证数据一致性。例如:

  1. 重试+死信队列:对消费失败的消息进行重试,超过一定重试次数后进入死信队列,处理死信队列的消息(补偿操作),并增加监控;
  2. 本地事务表+定时任务校对:事务消息的生产者在本地记录事务的状态到DB中,当下游服务消费消息后回调生产者通知事务的状态,并且事务消息的生产者需要定时检查自己的本地事务表,对于长时间未完成的事务进行处理。
  3. Saga模式:给每个子事务设置补偿操作,当下游服务消费消息失败时,发送消息通知上游服务执行事务补偿。

资料参考: RocketMQ 事务消息(阿里云官方文档)

技术写作如同代码开发,需要持续迭代。感谢您成为这篇博客的Reviewer,期待您的宝贵意见 ✍️

相关推荐
爬山算法12 小时前
Redis(73)如何处理Redis分布式锁的死锁问题?
数据库·redis·分布式
祈祷苍天赐我java之术14 小时前
Redis 数据类型与使用场景
java·开发语言·前端·redis·分布式·spring·bootstrap
猫林老师16 小时前
HarmonyOS线程模型与性能优化实战
数据库·分布式·harmonyos
在未来等你20 小时前
Elasticsearch面试精讲 Day 26:集群部署与配置最佳实践
大数据·分布式·elasticsearch·搜索引擎·面试
勤源科技21 小时前
分布式链路追踪中的上下文传播与一致性维护技术
分布式
互联网工匠21 小时前
分布式操作的一致性方案
分布式·架构
熊猫钓鱼>_>21 小时前
【案例实战】鸿蒙分布式智能办公应用的架构设计与性能优化
分布式·华为·harmonyos
没有bug.的程序员1 天前
金融支付分布式架构实战:从理论到生产级实现
java·分布式·微服务·金融·架构·分布式调度系统
在未来等你1 天前
Elasticsearch面试精讲 Day 25:Elasticsearch SQL与数据分析
大数据·分布式·elasticsearch·搜索引擎·面试
有一个好名字1 天前
万字 Apache ShardingSphere 完全指南:从分库分表到分布式数据库生态
数据库·分布式·apache