前世今生: 分布式事务1
要搞清分布式事务,我们先想一个问题,分布式事务产生的原因是什么?
如图所示:
CP是在保证数据强一致性前提下,尽量实现高可用(如过半写入)。
AP是在保证高可用的前提下,尽量实现数据一致性(如异步一致)。
在ACID里,I是最难实现的。Isolation包含四个层级,如下表所示。在XA中,一般可以做到RC就可以了。
事务隔离级别 | 事务隔离描述 | 解决的问题 | 不能解决的问题 |
最低1 | Read Uncommitted | 无 | 脏读 |
2 | Read Committed | 脏读 | 不可重复读 |
3 | Repeated Read | 脏读、不可重复读 | 幻读 |
最高4 | Serialization | 脏读、不可重复读、幻读 | 无 |
对于MySQL而言,它是通过RC+MVCC实现RR的效果。但ACID整体上是不靠谱的,为啥?
因为ACID只是满足数据隔离性,但没有做法并发控制。
如果面向于实际使用场景,我们把上图分布式实现区分一下,结果如下:
也就是说,真实分布式场景中,80%是柔性事物,20%是刚性事务,即使在金融行业,也是这样。刚性事务通过2PC实现;柔性事物同步模式通过Sagas实现,异步模式通过事务消息实现。
我们先看一下刚性事务的最终实现:2PC。如下图所示。在下图中,RM管理共享资源,如DB。TM负责管理全局事务,如分配事务唯一标识、监控事务的执行进度、并负责事务的提交、回滚、失败、恢复等。
2PC的缺点在于:它是同步阻塞模型、数据库锁定时间过长、全局锁(隔离级别串行化)并发低、不适合长事务场景(RM特别多的情况)。
3PC没有安全解决2PC的问题,但又引入了新的问题。由于实际场景几乎没人使用,因此我不做介绍。
在介绍了刚性事务2PC后,接下来我们介绍柔性事务。柔性事物的理念是BASE。
BASE理论指的是:
Basically Available(基本可用)
Soft state(柔性状态--->中间状态:业务中间态、数据中间态)
Eventually consistent(最终一致性)
我们举一个数据中间态的例子。一个转账业务,我们给转账业务数据分成两部分:可用金额要和冻结金额
接下来,我们看柔性事物的实现,先看Saga。
Saga本质是将一个分布式事务分为多个本地事务。每个本地事务只有执行和补偿。我们拿银行业余来说,有转账业务,转账业务的补偿事务就是:转账冲正,如下图所示。如果转账失败,就调用转账冲正进行事务补偿。
、
Saga的恢复模式分为:向后恢复(逆向补偿)和向前恢复(重试失败的事务)。
在隔离性方面,Sagas隔离是通过业务中间态实现的。例如金融系统的中间账户。
例如郭德纲向大魏转账,真实模式是:
郭德纲向中间账户转账失败,那么中间账户会删除记录。如果一段时间没删除,例如5s,那么中间账户就会想大魏转账。
前面提到的转账和冲正是互为逆方法。同样,CRUD中,insert和delete也是互为逆方法。因此我们需要为update操作提供逆方法。
那么,如何为update提供优雅的事务补偿呢?使用Seata AT。Seata AT就是在Sagas的基础上实现了自动补偿。目前自动补偿的方案都是往这个方向努力,看谁支持的 sql 语法更多,支持的db类型更多。
Seata AT实现的方法如下图:
未完待续...