摘要:我们可以通过本地消息表,来实现最终一致性,具体流程如下图调用外部服务,生成全局唯一的交易流水号。总结在不需要强一致性的业务场景下,都可以通过定时任务幂等操作来实现最终一致性。
背景
传统的单体应用不会横跨多个数据库,可以通过单机事务保证一致性。然而在海量数据的场景下,我需要对数据库做拆分,即分库分表,而Cobar、MyCat这类分库分表中间并不提供分布式事务的特性,并且基于二阶段提交的分布式事务性能较差,对于大多数业务场景来说,并不需要强一致,只需要保证最终一致性即可。
实践下面我们举个下订单的场景,总共有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
摘要:分布式事务初探前言不知道你是否遇到过这样的情况,去小卖铺买东西,付了钱,但是店主因为处理了一些其他事,居然忘记你付了钱,又叫你重新付。分布式事务解决方案有了上面的理论基础后,这里介绍开始介绍几种常见的分布式事务的解决方案。 分布式事务初探 前言 不知道你是否遇到过这样的情况,去小卖铺买东西,付了钱,但是店主因为处理了一些其他事,居然忘记你付了钱,又叫你重新付。又或者在网上购物明明已经扣...
摘要:对于设计分布式系统来说不仅仅是分布式事务的架构师来说,就是你的入门理论。分布式事务解决方案有了上面的理论基础后,这里介绍开始介绍几种常见的分布式事务的解决方案。是否真的要分布式事务在说方案之前,首先你一 事务的具体定义:事务提供一种机制将一个活动涉及的所有操作纳入到一个不可分割的执行单元,组成事务的所有操作只有在所有操作均能正常执行的情况下方能提交,只要其中任一操作执行失败,都将导致整...
摘要:降级往往会指定不同的级别,面临不同的异常等级执行不同的处理。谈谈你对和的认识两者关系具体可以看公众号阿里巴巴中间件的这篇文章独家解读从微服务框架到微服务生态与并不是竞争关系,作为成熟的框架,其易用性扩展性和健壮性已得到业界的认可。 该文已加入笔主的开源项目——JavaGuide(一份涵盖大部分Java程序员所需要掌握的核心知识的文档类项目),地址:https://github.com/...
摘要:降级往往会指定不同的级别,面临不同的异常等级执行不同的处理。谈谈你对和的认识两者关系具体可以看公众号阿里巴巴中间件的这篇文章独家解读从微服务框架到微服务生态与并不是竞争关系,作为成熟的框架,其易用性扩展性和健壮性已得到业界的认可。 该文已加入笔主的开源项目——JavaGuide(一份涵盖大部分Java程序员所需要掌握的核心知识的文档类项目),地址:https://github.com/...
阅读 1916·2021-11-15 11:38
阅读 2369·2021-09-22 10:02
阅读 898·2021-09-06 15:02
阅读 3093·2021-08-27 13:12
阅读 1077·2019-08-30 14:20
阅读 2187·2019-08-29 15:08
阅读 470·2019-08-29 14:08
阅读 1595·2019-08-29 13:43