0 分布式事务-微服务系统的最大挑战
单体系统通过事务解决的问题
- 数据的并发访问、修改
- 不同请求之间的数据隔离- 事务
- 一个业务请求修改多个数据,保证都完成或失败
- 发生异常时的数据回滚
- Springcloud微服务系统架构
Event Sourcing 系统实例
分布式事务
定义
在分布式系统中实现事务。
1 CAP 定理
1.1 概念
CAP 理论在分布式系统中:
- 一致性
多个节点的数据是否强一致 - 可用性
分布式服务能一直保证可用状态。当用户发出一个请求后,服务能在有限时间内返回结果 - 分区容忍性
对网络分区的容忍性
对于共享数据系统,最多只能同时拥有CAP其中的两个,无法三者兼顾。
- 任两者的组合都有其适用场景
- 真实系统应当是ACID与BASE混合体
- 不同类型的业务可以也应当区别对待
- 分区容忍性不可或缺
分布式系统中,最重要的是满足业务需求,而不是追求抽象、绝对的系统特性。
2.2 中间件实例
- 优先选择AP,弱化C
Cassandra、Dynamo 等
- 优先选择CP,弱化A
HBase、MongoDB 等
2 BASE 理论
2.1 核心思想
- 基本可用(BasicallyAvailable)
分布式系统在出现故障时,允许损失部分的可用性来保证核心可用。 - 软状态(SoftState)
允许分布式系统存在中间状态,该中间状态不会影响到系统的整体可用性。 - 最终一致性(EventualConsistency)
分布式系统中的所有副本数据经过一定时间后,最终能够达到一致的状态
2.2 数据的一致性模型
分类
- 强一致性
数据更新成功后,任意时刻所有副本中的数据都是一致的。一般采用同步实现 - 弱一致性
数据更新成功后,系统不承诺立即可以读到最新写入的值,也不承诺具体多久后可读到 - 最终一致性
弱一致性的一种形式,数据更新成功后,系统不承诺立即可以返回最新写入的值,但是保证最终会返回上一次更新操作的值
分布式系统数据的强一致性、弱一致性和最终一致性可通过Quorum NRW算法分析。
3 分布式事务的解决方案
- 异步校对数据
支付宝、微信支付主动查询支付状态、对账单的形式; - 基于可靠消息(MQ)
异步场景;通用性较强;拓展性较高 - TCC编程式解决方案
严选、阿里、蚂蚁金服自己封装的DTX
3.1 实现思路
理想状态
像单机数据库事务一样,多个数据库自动通过某种协调机制,实现跨数据库节点的一致性。
- 使用场景
要求严格的一致性,比如金融交易类业务。
一般情况
可容忍一段时间的数据不一致,最终通过超时终止,调度补偿等方式,实现数据的最终状态一致性。
- 使用场景
准实时或非实时的处理,比如 T+1 的各类操作,或者电商类操作。
3.2 实现方案
3.2.1 XA方案
3.2.2 TCC方案
三阶段
- Try
对各个服务的资源做检测,对资源进行提前锁定或者预留 - Confirm
在各个服务中执行实际的操作 - Cancel
如果任何一个服务的业务方法执行出错,那么这里就需要进行补偿,即执行已操作成功的业务逻辑的回滚操作
4.2 跨行转账案例
涉及到两个银行的分布式事务,如果用TCC实现:
Try阶段
先把两个银行账户中的资金给它冻结住,不让操作
Confirm阶段
执行实际的转账操作,A银行账户的资金扣减,B银行账户的资金增加
Cancel阶段
如果任何一个银行的操作执行失败,那么就需要回滚进行补偿
比如A银行账户如果已经扣减了,但是B银行账户资金增加失败了,那么就得把A银行账户资金给加回去。
该方案很少使用,但也有使用场景。
因为这个事务的回滚实际上严重依赖于你自己写代码来回滚和补偿了,会造成补偿代码巨大,非常恶心!
比如说我们,一般来说和钱相关的支付、交易等相关的场景,我们会用TCC,严格严格保证分布式事务要么全部成功,要么全部自动回滚,严格保证资金的正确性!
4.3 适用场景
除非你是真的一致性要求太高,是系统中核心之核心的场景!
常见的就是资金类的场景,那可以用TCC方案,自己编写大量的业务逻辑,自己判断一个事务中的各个环节是否ok,不ok就执行补偿/回滚代码。
而且最好是你的各个业务执行的时间都比较短。
但尽量别这么搞,自己手写回滚逻辑,或者是补偿逻辑,实在太恶心了,业务代码也很难维护。
4.4 方案示意图