资讯专栏INFORMATION COLUMN

本地消息表实现最终一致性

Clect / 1519人阅读

摘要:我们可以通过本地消息表,来实现最终一致性,具体流程如下图调用外部服务,生成全局唯一的交易流水号。总结在不需要强一致性的业务场景下,都可以通过定时任务幂等操作来实现最终一致性。

背景

传统的单体应用不会横跨多个数据库,可以通过单机事务保证一致性。然而在海量数据的场景下,我需要对数据库做拆分,即分库分表,而CobarMyCat这类分库分表中间并不提供分布式事务的特性,并且基于二阶段提交的分布式事务性能较差,对于大多数业务场景来说,并不需要强一致,只需要保证最终一致性即可。

实践

下面我们举个下订单的场景,总共有3个实体,商品用户订单,我们按照user_id来sharding。所以相同user_id用户订单在同一个物理库下,而商品表中不存在user_id,所以商品表在不同的物理库下。

下订单的场景,主要涉及到两个事务操作,扣减库存生成订单,因为两个操作涉及不同的数据库,所以无法保证强一致性。

我们可以通过本地消息表,来实现最终一致性,具体流程如下图:

调用外部服务,生成全局唯一的交易流水号trans_id

事务一:1) 扣减库存 2) 根据流水单号,生成对应商品的冻结记录。消息表主要由商品ID交易流水号冻结数消息状态这四个字段构成,因为消息表和商品表在同一个物理库下,所以TX1中的操作1和操作2是可以构成事务操作的。冻结记录的状态有三种:已冻结释放已售出释放未售出。冻结记录的初始状态为已冻结

事务一如果成功,则进行事务二;如果事务一失败,则直接返回。

事务二:根据交易流水号trans_id生成订单,订单的状态有三种:未支付已支付超时,订单的初始状态为未支付

若订单创建成功,则进行后续的支付流程。

如果事务二失败,由于网络抖动超时等原因,不一定是真的生成订单失败,即 在事务二失败的情况下,可能生成了订单,也可能确实没有生成订单。

定时任务一:设置一个每隔15分钟的定时任务(即一个订单必须在15分钟内完成支付),从订单表里捞出最近半小时内的所有订单,对每一个订单做如下处理:若订单超时未支付,开启事务SELECT FOR UPDATE 锁住该订单,即用悲观锁阻止用户对订单进行支付等操作,然后通过订单的trans_id去冻结表更新对应冻结记录的状态,置为释放未售出,并回滚商品数量,回滚商品的操作完成后,将订单状态置为超时,若事务中调用的回滚商品数量的服务失败,则可以发出报警人工处理,或通过更长时间的定时任务去处理;若订单为已支付,则将冻结表中记录的状态置为释放已售出

定时任务二:因为存在事务一成功,而事务二的订单确实没有创建成功的情况,这样会冻结一部分商品的数量,所以可以捞取出 创建超过10分钟 状态为已冻结的所有冻结记录,根据每个冻结记录的trans_id去订单表查询,若不存在对应的订单,则将冻结记录的状态更新为释放未售出,并回滚商品数量。

另一个需要注意的点,在定时任务一中,对于超时未支付的订单,会先回滚冻结表,然后将订单状态置为超时,但这最后一步将订单置为超时可能会失败,这样会出现不一致的状态,即订单状态为未支付,而冻结记录的状态为释放未售出。所以,在支付的时候需要做一个前置校验,检查冻结记录的状态是否为已冻结,若不是,则拒绝支付。

变种

在上面这种模型的基础上,还有一种变种,如下图:

即在TX2失败的情况下,跳转到TX3

根据trans_id查询订单,若订单不存在,则直接将冻结记录置为释放未售出,并回滚库存;若订单存在,则说明TX2因为网络抖动等原因而失败,其实订单创建成功,则进行正常的支付流程。

需要注意的是:根据trans_id查询订单的时候,一定要开启事务,这样才会强制走主库,若不开启事务,则会走备库,因为MySQL主从同步延迟的问题,备库很可能无法查询到订单,从而回滚库存,这显然是错误的。

变种的优点

将定时任务的压力均匀地分配到每一次调用中,提高数据库的可用性。

总结

在不需要强一致性的业务场景下,都可以通过定时任务+幂等操作来实现最终一致性。

以上。

原文链接

https://segmentfault.com/a/11...

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/47411.html

相关文章

  • 分布式事务初探

    摘要:分布式事务初探前言不知道你是否遇到过这样的情况,去小卖铺买东西,付了钱,但是店主因为处理了一些其他事,居然忘记你付了钱,又叫你重新付。分布式事务解决方案有了上面的理论基础后,这里介绍开始介绍几种常见的分布式事务的解决方案。 分布式事务初探 前言 不知道你是否遇到过这样的情况,去小卖铺买东西,付了钱,但是店主因为处理了一些其他事,居然忘记你付了钱,又叫你重新付。又或者在网上购物明明已经扣...

    TalkingData 评论0 收藏0
  • 分布式事务解决方案实战

    摘要:对于设计分布式系统来说不仅仅是分布式事务的架构师来说,就是你的入门理论。分布式事务解决方案有了上面的理论基础后,这里介绍开始介绍几种常见的分布式事务的解决方案。是否真的要分布式事务在说方案之前,首先你一 事务的具体定义:事务提供一种机制将一个活动涉及的所有操作纳入到一个不可分割的执行单元,组成事务的所有操作只有在所有操作均能正常执行的情况下方能提交,只要其中任一操作执行失败,都将导致整...

    i_garfileo 评论0 收藏0
  • 浅析分布式事务

    摘要:总的来说,理论面向的是大型高可用可扩展的分布式系统,和传统的事物特性是相反的,它完全不同于的强一致性模型,而是通过牺牲强一致性来获得可用性,并允许数据在一段时间内是不一致的,但最终达到一致状态。 一、单机事务 1.1 ACID特性 1.1.1 原子性 一个事务(transaction)中的所有操作,要么全部完成,要么全部不完成,不会结束在中间某个环节。 事务在执行过程中发生错误,会被回...

    韩冰 评论0 收藏0
  • 【面试精选】关于大型网站系统架构你不得不懂的10个问题

    摘要:降级往往会指定不同的级别,面临不同的异常等级执行不同的处理。谈谈你对和的认识两者关系具体可以看公众号阿里巴巴中间件的这篇文章独家解读从微服务框架到微服务生态与并不是竞争关系,作为成熟的框架,其易用性扩展性和健壮性已得到业界的认可。 该文已加入笔主的开源项目——JavaGuide(一份涵盖大部分Java程序员所需要掌握的核心知识的文档类项目),地址:https://github.com/...

    leiyi 评论0 收藏0
  • 【面试精选】关于大型网站系统架构你不得不懂的10个问题

    摘要:降级往往会指定不同的级别,面临不同的异常等级执行不同的处理。谈谈你对和的认识两者关系具体可以看公众号阿里巴巴中间件的这篇文章独家解读从微服务框架到微服务生态与并不是竞争关系,作为成熟的框架,其易用性扩展性和健壮性已得到业界的认可。 该文已加入笔主的开源项目——JavaGuide(一份涵盖大部分Java程序员所需要掌握的核心知识的文档类项目),地址:https://github.com/...

    luqiuwen 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<