在事务里发送普通消息引起的线上问题

记录一次线上问题事件:

实习生小A在做一个需求时,需要从订单系统中生产业务消息,仓储系统中的消息订阅者进行消费。在这个过程中,订单、仓储系统都需要查询并且更新order表获取字段updateTime的值,但是系统上线后发现updateTime值更新异常,仓储系统查询到了订单update前的数据。

排查流程

  1. 怀疑是多个消息到达仓储系统,如果订单update更新时,仓储在消费多消息时将订单更新的updateTime的值进行覆盖。
    应对这种情况,小A对两个系统的业务按照订单维度进行加锁。
    但是问题继续出现了。。。。。。
  2. 查看了关键流程的日志记录,发现事务均提交成功,并且数据事务隔离级别都是RR。也不存在主从数据库的情况。
    日志没发现啥异常
  3. 小A请求组内成员大佬,得出:发送MQ消息得在事务提交成功之后,在进行大事务操作时,需要对代码进行细致检查,或者对实现方式进行思考。

解决方案

对于事务中发送消息的情况

  1. 消息发送的前提,最好是在事务提交成功之后进行投递。
  2. 可以使用事务消息。

部分MQ产品提供事务消息特性,允许生产者先发送半事务消息,在本地事务完成后提交事务,此时消息队列才会真正投递消息给消费者。若本地事务失败,则MQ不会投递这条消息。

  1. 潜在的问题
  1. 若只是简单地将消息发送置于订单系统事务中,而未做特殊处理,一旦订单事务回滚,如果没有相应的事务消息支持机制,可能会出现消息已发送但订单记录未成功插入数据库的情况,反之亦然,这会导致数据不一致。
  2. 另一方面,即使消息成功发送到MQ,仓储系统在消费消息并执行事务操作时,其自身事务的失败并不会自动回滚订单系统的事务,因此也需要额外的补偿机制来保证最终一致性。
  3. 如果希望订单系统的数据库事务和消息发送事务保持原子性,即要么订单创建成功且消息发送成功,要么两者都失败回滚,您可以采用消息队列提供的事务消息功能。例如,某些MQ产品支持XA事务或者两阶段提交来保证分布式事务的一致性。
  1. 对于不同系统都需要更新相同表资源,技术方案的设计是不是有问题。

额外小知识

在分布式系统中,尤其是涉及到多个子系统共同操作同一份数据时,确实会面临一致性问题。针对您所描述的场景,可以补充以下几个方面的小知识和解决思路:

  1. 分布式事务

    • 分布式事务是指跨越多个数据库或服务的事务,为确保数据一致性,常见的解决方案有二阶段提交(2PC)、三阶段提交(3PC)、Saga模式、TCC(Try-Confirm-Cancel)模式等。其中,部分MQ产品支持的事务消息正是基于这些理论的一种实现方式。
  2. 消息顺序性

    • 在此案例中,由于订单和仓储系统都在更新updateTime,要确保更新顺序,除了通过事务机制,还可以借助消息队列的顺序消息功能,确保消息严格按序消费。
  3. 资源竞争与锁优化

    • 即使在单个系统内部,面对多线程并发访问同一资源(如updateTime),也需合理设计锁机制,避免死锁和并发问题。此外,可考虑使用乐观锁或悲观锁,甚至条件变量等手段提高并发性能。
  4. 领域驱动设计(DDD)和数据模型优化

    • 在设计系统时,可以运用领域驱动设计方法,明确区分各个子系统的职责边界,减少共享资源的竞争。例如,是否可以通过增加一个只由仓储系统维护的状态字段,而不是直接更新公共的updateTime字段。
  5. 异步解耦

    • 异步消息队列的引入就是为了实现系统间的解耦,但在实际操作中,确实需要注意消息生产和消费的事务一致性问题。在本例中,改为事务提交后再发送消息是一种有效解决方案。
  6. 幂等性设计

    • 确保消息消费者的业务逻辑具备幂等性,即使重复收到同一条消息也能正确处理,这对于解决消息重发、乱序等问题十分重要。

对于上述场景,建议调整为事务提交后发送消息,并根据实际情况选择适合的分布式事务解决方案。同时,重新审视系统间交互的设计,尽量减少对同一资源的竞争和更新冲突。

  • 29
    点赞
  • 28
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

JF Coder

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值