保障分布式系统数据一致性
Posted 守拙的厨子
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了保障分布式系统数据一致性相关的知识,希望对你有一定的参考价值。
对于现在普遍的分布式系统的架构和设计, 在提升系统可用性的同时, 各个子系统之间的数据一致性问题也日益凸显出来, 很多公司都推出了符合自己业务需求的解决方案
具体业务场景如下,比如一个业务操作,如果同时调用服务 A、B、C,需要满足要么同时成功;要么同时失败。A、B、C 可能是多个不同部门开发、部署在不同服务器上的远程服务。
在分布式系统来说,如果不想牺牲一致性,CAP 理论告诉我们只能放弃可用性,这显然不能接受.
在工程实践上,为了保障系统的可用性,互联网系统大多将强一致性需求转换成最终一致性的需求,并通过系统执行幂等性的保证,保证数据的最终一致性
1.规避分布式事务——业务整合
一般来说不可取
2. ebay模式
将需要分布式处理的任务通过消息日志的方式来异步执行。消息日志可以存储到本地文本、数据库或消息队列,再通过业务规则自动或人工发起重试。人工重试更多的是应用于支付场景,通过对账系统对事后问题的处理
BASE (basically available, soft state, eventually consistent)
BASE 的可用性是通过支持局部故障而不是系统全局故障来实现的, 如果将用户分区在 5 个数据库服务器上,BASE 设计鼓励类似的处理方式,一个用户数据库的故障只影响这台特定主机那 20% 的用户。这里不涉及任何魔法,不过它确实可以带来更高的可感知的系统可用性
场景如下, 产生一笔交易, 第一步,需要在交易表增加记录. 第二部需要修改用户金额表, 买家金额减少, 卖家金额增加. 而且卖家与买家可能分布在不同的数据库服务器
u
对于每一个分库, 增加一个更新记录表 updates_applied 来记录已经处理过的消息(处理完一笔, 记录这样一条消息, 放在同一个事务里面), 这样做是为了保障处理的幂等性.
伪代码如下:
第一阶段: 通过本地的数据库的事务保障,增加了 transaction 表及消息队列, 消息队列中记录了本次事务分别要做的事情的步骤
第二阶段: 分别读出消息队列(但不删除),通过判断更新记录表 updates_applied 来检测相关记录是否被执行
针对不同的用户记录交易记录, 假设根据用户id分库分表, 分别开启事务未被执行的记录会修改 user 表,
然后增加一条操作记 录到 updates_applied,这两个步骤要保证在同一个数据库实例的事务中来完成.
事务执行成功之后再删除队列中对应的消息.
这样做的好处是: 对事务中的每一个步骤都记录到消息中, 相当于对做的事情记录了日志. 可以对日志记录进行不断的重试操作. 但是未考虑到回滚的动作. 比如转账失败, 或者买家的余额不足这种情况下, 卖家方的操作如何回滚.
3. 蘑菇街交易创建过程中的分布式一致性方案
交易创建的一般性流程
面临的问题:
每个功能点的实现都可能会依赖外部服务。那么如何保证各个服务之间的数据是一致的呢?比
如锁定优惠券服务调用超时了,不能确定到底有没有锁券成功,该如何处理?再比如锁券成功
了,但是扣减库存失败了,该如何处理?
方案选型
1. 服务依赖过多, 会带来管理复杂性增加和稳定性风险增大的问题。试想如果我们强依赖 10个服务,
9个都执行成功了,最后一个执行失败了,那么是不是前面9个都要回滚掉? 这个成本还是非常高的。
所以在拆分大的流程为多个小的本地事务的前提下,对于非实时、非强一致性的关联业务写入,
在本地事务执行成功后,我们选择发消息通知、关联事务异步化执行的方案.
2. 消息通知往往不能保证100%成功; 且消息通知后,接收方业务是否能执行成功还是未知数
第一个问题: 通过重试来解决, 保证消息一定要到达broker
第二个问题: 订阅方消费消息的ack机制来保障消息一定消费成功. 消息可能被重发,
所以业务方在处理消息的时候需要做到幂等性.
3. 对于需要实时同步做, 有强一致性需求的业务场景, 在交易创建过程中, 锁券和扣减库存是这样的两个典型场景
乍一看,必须要 引入分布式事务框架才能解决。但引入非常重的类似二阶段提交分布式事务框架会带来 复杂性的急剧上升;在电商领域,绝对的强一致是过于理想化的,我们可以选择准实时的最终一致性
a. 我们在交易创建流程中,首先创建一个不可见订单,然后在同步调用锁券和扣减库存时,针对调用异常(失败或者超时),发出废单消息到MQ
b. 如果消息发 送失败,本地会做时间阶梯式的异步重试
c. 优惠券系统和库存系统收到消息后,会进行判断是否需要做业务回滚,这样就准实时地保证了多个本地事务的最终一致性
以上是关于保障分布式系统数据一致性的主要内容,如果未能解决你的问题,请参考以下文章