上一篇介绍了2PC和3PC,其主要是为了解决分布式事务中的数据一致问题。这篇就是来了解另外一种
事务的实现方式TCC以及柔性事务。
柔性事务其实是相对传统的事务而言的。我们对传统事务称呼为刚性事务,重视强一致性。而柔性事务更在意最终一致性。
刚性事务
遵循ACID原则,重视强一致性。
柔性事务
遵循BASE理论,实现“基本可用、最终一致”。
ACID应该是所有开发人员最开始接触的事务原则了。ACID是Atomicity(原子性)、Consistency(一致性)、
Isolation(隔离性)、Durability(持久性)的四个首字母。其
原子性(Atomicity)
整个事务中的所有操作,要么全部完成,要么全部不完成,不可能停滞在中间某个环节。事务在执行过程中发生错误,会被回滚到事务开始前的状态,就像这个事务从来没有执行过一样。
一致性(Consistency)
一个事务可以封装状态改变(除非它是一个只读的)。事务必须保证系统始终处于一致的状态,不管在任何给定的时间里,并发事务有多少。
隔离性(Isolation)
在并发环境中,并发的事务是相互隔离的,一个事务的执行不能被其他事务干扰。
也就是说,不同的事务并发操纵相同的数据时,每个事务都有各自完整的数据空间,即一个事务内部的操作及使用的数据对其他并发事务是隔离的,并发执行的各个事务之间不能互相干扰。
持久性(Durability)
在事务完成以后,该事务对数据所作的更改便持久的保存,并不会被回滚。
BASE是Basically Available(基本可用),Soft state(软状态),和 Eventually consistent(最终一致性)三个短语的缩写。
Basically Available(基本可用)
基本可用指的是分布式系统在出现未知故障的时候,允许损失部分可用性来。可能是响应时间上的损失,也可能是停止部分服务。
软状态
允许系统中的数据存在中间状态,并认为该中间状态不影响系统可用性。
最终一致性
和之前硬事务的强一致性不同,此处允许系统中各个备份数据在某一时间内存在不一致的情况,但是在一段时间数据同步之后,最终需要能够达到一个一致的状态。
名称 | 描述 |
---|---|
因果一致性 | 当一项业务存在顺序操作,后一项操作基于前一项的数据的时候,必须保证后一项操作的时候获得之前项的数据为最新数据,但是和此业务无关的查询则不存在限制。简单的说就是A在B操作之前,那么进行B操作的时候需要保证获得的A数据为最新,而与他们毫无相关的C则不受此影响 |
读己之所写 | 进程A更新数据后,假如这个值是最新值,那么它应该总是可以访问到的。(它不应该访问到其他副本的旧值) |
会话一致性 | 类似上述的会话版本,某次会话时对数据的更新,此会话期间进行更新的新值,会话应该总能访问到 |
单调读一致性 | 如果进程已经看到过数据对象的某个值,那么任何后续访问都不会返回在那个值之前的值 |
单调写一致性 | 一个系统需要能够保证来自同一个进程的写操作被顺序地执行。 |
TCC方案是可能是目前最火的一种柔性事务方案了。关于TCC(Try-Confirm-Cancel)的概念,最早是由Pat Helland于2007年发表的一篇名为《Life beyond Distributed Transactions:an Apostate’s Opinion》的论文提出。在该论文中,TCC还是以Tentative-Confirmation-Cancellation命名。正式以Try-Confirm-Cancel作为名称的是Atomikos公司,其注册了TCC商标。国内最早关于TCC的报道,应该是InfoQ上对阿里程立博士的一篇采访。经过程博士的这一次传道之后,TCC在国内逐渐被大家广为了解并接受。
根据名称我们可以知道TCC存在三个操作。try,confirm,cancel。这三个操作被分为了两个阶段分别对应:阶段一(try0),阶段二(confirm/cancel)
TCC被分为两个阶段,简单的说在try阶段完成业务检查同时完成资源的锁定。在confirm/cancel阶段根据第一阶段的结果进行判断是进行提交还是取消
try-尝试阶段
其主要操作有两部分
confirm-提交阶段
当try完成资源锁定后在confirm阶段进行业务执行。在保证事务幂等性的前提下,对预留的业务资源进行业务操作
cancel-取消
当try节点在进行业务检查或者资源锁定的时候出现异常,则进入此阶段。在保证事务幂等的前提下,对预留资源进行取消或者回滚操作。
上面的介绍描述了TCC每个阶段的任务,但是没有一个具体的例子结合会让人觉得困惑。下面我就简单举个转账的例子来简单的描述下TCC逻辑
场景
现在存在三个账户 张三、李四、王五。现在张三要向李四转账10块,李四需要向王五转账10块。最终的结果应该是张三少了10元、王五多了10元。我们将此作为一个事务。
try阶段
confirm阶段
当try阶段完成所有的资源锁定后,可以进入confirm阶段,在此阶段事务管理器根据之前事务号找到需要执行的事务,并依次发出执行事务的请求。事务开始执行。
cancel阶段
当try阶段,进行业务检查没有通过,或是资源锁定失败的情况。在此阶段事务管理器根据之前事务号找到需要执行的事务,并根据当时事务状态取消各个业务操作。
在TCC模式下,出现异常主要是使用日志或者队列进行重试,来保证最终一致性。假如try阶段出现异常,则会触发cancel操作。而cancel操作执行的时候发生异常,系统会使用日志或者队列中是事务信息重试cancel操作。直到事务被成功取消。假如是confirm阶段则是根据事务状态来进行重试,老保证事务完成。当然一般来说我们会有个重试次数的限制,当重试超过限制会对错误信息进行保存,后续由人工进行干涉。
TCC的优点是,相比二阶段提交对资源的占用相对较少。在2PC中,在整个事务中都在对资源进行占用。这会导致性能下降。
TCC的缺点也很明显,TCC将部分事务逻辑提到业务层面。需要在业务上对资源进行变更。对于业务方面侵入性比较高,传统业务只需要一个修改接口,但使用TCC模式需要设置try、confirm、cancel三个接口。尤其对于老旧项目会有比较大的改造成本。
使用开源的TCC框架
明白了TCC的有能力的开发或公司可以搭建自己的TCC框架,但是一个稳定可靠的TCC框架需要很高的成本。所以也可以选择开源的TCC框架,比如tcc-transaction