分布式事务-理论篇

分布式事务-理论篇

事务是什么?事务是一个独立的工作单元。

事务有哪些特征?

ACID-原子性(atomicity),一致性(consistency),隔离性(isolation),持久性(durability)。这些概念我是读《高性能MySQL》这本书的时候重温的,加深我对MySQL理解的还有个MVCC的概念。以及存储引擎和数据存储数据结构B+Tree等内容,了解数据库底层实现数据结构有助于理解SQL的一些特性。例如,索引的最左原则。

分布式事务

CAP和BASE理论

分布式事务通常指的是分布式系统间的事务处理,说起分布式系统就不得不提CAP和BASE理论。
2000年7月,来自夹肉大学伯克利分销的Eric Brewer教授在 ACM PODC(Principles of Distributed Computing)会议上,首次提出了著名的CAP猜想。2年后,来自麻省理工学院的Seth Gilbert和Nancy Lynch从理论上证明了Brewer教授CAP猜想的可行性,从此,CAP理论正式在学术上成为了分布式计算领域的公认定理,并深深地影响了分布式计算的发展。
CAP理论告诉我们,一个分布式系统不可能同事满足一致性(C: Consistency)、可用性(A: Avaliability)和分区容错性(P: Partition tolerance)这三个基本需求,最多只能同时满足其中两个。
CAP
从CAP定理中我们可以看出,一个分布式系统不可能同时满足一致性、可用性和分区容错性这三个需求。另一方面需要明确的是,对于分布式系统而言,分区容错性是一个基本要求。因此我们主要的经历花费在如何根据业务特点在C(一致性)和A(可用性)之间寻求平衡。

BASE理论
BASE是Basically Available(基本可用),Soft state(软状态), Eventually consistent(最终一致性)是哪个语句的缩写,是由来自eBay的架构师Dan Pritchett在其文章BASE: An Acid Alternative中第一次明确提出的。BASE是对CAP中一致性权衡的结论,其来源于对大规模互联网系统分布式实践的总结,是基于CAP定理逐步演化而来的,核心思想是即使无法做到强一致性,但是每个应用都可以根据自身的业务特点,采用适当的方式来使系统达到最终一致性。这些概念我是读《从Paxos到ZooKeeper》这本书的时候了解到的。

分布式事务系统

分布式事务在现在的项目中很常见,常见会引入分布式事务的架构如下图:
事务1
如果在一个服务中同一个方法逻辑我们需要像Mysql、Redis、MQ等独立应用中插入数据,此时需要考虑分布式事务的处理。例如用户注册,我们需要将用户信息落库,存入缓存,还要发送邮箱确认邮件通知。

事务2
如果在一个服务中需要对Mysql操作同时需要其他服务配合相关操作,此时也需要考虑分布式事务问题。例如订单服务、商品库存服务,我们在订单服务中心下单,还需要在商品服务中进行库存扣除。

解决方案

说起解决分布式事务问题,不得不提一个组织。The Open Group(https://www.opengroup.org/), 这个组织是领导厂商中立的开放的技术标准和认证开发,帮助企业通过技术标准实现业务目标。我们经常看到的XA协议就是出自这里,在这些标准的制定者中有一个我们非常熟悉的公司。是的,就是被美国举国家之力打压的中国公司”华为”! 这也说明了,华为的技术实力。

DTP事务模型

X/OPEN组织为解决分布式事务,首先制定了分布式事务模型-DTP(Distributed Transaction Processing)事务模型:
A. 应用程序(Application Program: AP) - 定义事务边界(事务的开始、结束)
B. 资源管理器(Resource Manager: RM) - 存储数据的服务(MySQL、Redis、MQ或其他服务)
C. 事务管理器(Transaction Manager: TM) - 监控、提交、回滚事务
D. 通信资源管理器(Communcation Resource Manager: CRM) - 管理协调通信资源
E. 通信协议 - 定义了资源管理器、事务管理器、资源之间的通信协议
其中,AP和TM以及RM通信,TM和RM之间互相通信。DTP模型定义了XA接口,TM和RM通过XA接口进行双向通信。TM通知RM提交或回滚事务,RM把执行结果通知给TM以便TM决策对其他RM的下一步指示。AP和RM之间通过RM提供的native api进行通信,像我经常使用的java语言有一个JDBC规范,各个厂商为实现JDBC规范提供的资源操作驱动程序。
DTP模型

XA接口规范

X/OPEN组织为解决分布式事务,还定义了一个XA接口规范。如上图所示TM和RM通过XA接口进行双向通信。
目前各大数据库厂商都提供了对XA的支持,XA协议采用两阶段提交方式来管理分布式事务。XA解耦提供TM和RM支架通信的标准接口,包括但不限于事务注册、开始、回滚、提交等操作。协议包括两套函数,以xa_开头及ax_开头。TM对RM的常见操作函数有:

  1. xa_open, xa_close: 建立和关闭与资源管理的连接;
  2. xa_start, xa_end: 开始和结束一个本地事务;
  3. xa_prepare, xa_commit, xa_rollback: 预提交、提交和回滚一个本地事务;
  4. xa_recover: 回滚一个已经进行预提交的事务;
  5. ax_ 开头的函数使资源管理器可以动态地在事务管理器中进行注册,并可以对XID(TRANSACTION IDS)进行操作;
  6. ax_reg, ax_unreg: 允许一个资源管理器在一个事务管理器中动态注册或撤销注册。
2PC与3PC

在多数据源的情况下可以使用Atomikos插件实现事务管理器并且该插件支持事务传播。
在多服务场景下也可以使用Atomikos,在不需要支持事务传播性的场景下可以使用:

1. TCC事务补偿机制;
2. 最终消息一致性;
3. 最大努力通知。

在长期的探索和研究过程中,前辈们总结了很多分布式事务处理方案。比较知名的是两阶段提交和三阶段提交。
2PC是Two Phase Commit的缩写,两阶段的提交就是把事务的提交分成两个阶段来完成。在DTP事务模型中,我们将事务管理器成为TM、资源管理器成为RM。在2PC中我们经常称为事务的协调者和参与者。

2PC
A. 第一阶段:提交事务请求

  1. 事务询问 - 协调者向所有参与者发送事务内容,询问是否可以执行事务提交操作,并等待参与者的响应;
  2. 执行事务 - 各参与者执行事务操作,并将Undo和Redo信息记入事务日志;
  3. 各参与者响应协调者事务准备请求 - 如果所有参与者都准备Yes,那么事务可以进行。如果有参与者回复No,那么协调者通知所有参与者回滚事务准备。
    B. 第二阶段:执行事务提交
  4. 发送提交请求 - 如果所有参与者都回复Yes,协调者向所有参与者发送Commit请求;
  5. 事务提交 - 参与者收到Commit请求后,执行本地事务提交、释放资源并响应执行结果给协调者;
  6. 完成事务 - 协调者收到所有参与者的ACK消息后,完成事务;
  7. 发送回滚请求 - 任一参与者发送No,协调者向所有参与者发送Rollback请求;
  8. 事务回滚 - 参与者收到Rollback请求后,使用阶段一中记录的Undo日志来执行事务回滚操作,释放资源并响应协调者执行结果;
  9. 中断事务 - 协调者收到所有参与者的ACK消息后,完成事务中断。

两阶段提交优缺点:
优点:

1. 原理简单;
2. 实现方便。

缺点:

1. 同步阻塞:两阶段提交属于强一致性,会导致参与者处于阻塞状态影响系统西能;
2. 单点故障:协调者单点故障;
3. 脑裂:部分参与者执行Commit导致数据不一致,可能是因为服务宕机或者网络原因。

由于两阶段提交存在以上问题,X/OPEN组织引入了3PC(CanCommit, PreCommit, Do Commit)分为三个阶段提交事务。比较两阶段三阶段做了两点改动:1. 引入超时机制;2. 将两阶段提交协议中的“提交事务请求”过程一分为二,行程了CanCommit, PreCommit, Do Commit三个阶段。
3PC

A. 第一阶段:CanCommit

  1. 事务询问 - 协调者向所有参与者发送包含事务内容的CanCommit请求,询问是否可以执行事务提交操作,并进入等待状态;
  2. 参与者响应 - 参与者根据事务请求内容结合自身情况判断是否可以顺利执行事务,如果可以顺利执行返回Yes,并进入准备状态,否则返回No。

B. 第二阶段:PreCommit - 根据阶段一中参与者的响应内容判断下一步操作是PreCommit还是中断事务。
执行事务提交:

1. 发送与提交请求 - 协调者向参与者发送PreCommit请求,参与者进入Prepared阶段;
2. 事务预提交 - 参与者执行事务操作并记录Undo和Redo日志;
3. 响应执行结果 - 参与者执行成功返回ACK。

中断事务:
协调者向参与者发送abort请求,无论参与者是否收到或者是等待超时,参与者都会中断事务。

C. 第三阶段:DoCommit
执行提交:

1. 发送提交请求 - 协调者收到参与者ACK后,发送DoCommit请求。协调者从Prepared状态转换为Commit状态;
2. 参与者执行完commit之后,释放资源并向协调者发送ACK响应。

中断事务:

1. 协调者向参与者发送abort请求,参与者收到请求后利用B中记录的Undo日志进行事务回滚,完成后释放资源并响应协调者ACK信息。
2. 协调者如果收到任一参与者ACK后,将中断事务。

三阶段提交优缺点:
优点:

1. 相对于两阶段提交,三阶段最大优点是降低了参与者的阻塞范围;
2. 增加了出现单点故障后事务默认处理方案。

缺点:

1. 同步阻塞:三阶段提交仍然属于强一致性,会导致参与者处于阻塞状态,相对两阶段只是减小了出现阻塞的范围;
2. 单点故障:在参与者收到PreCommit预提交后,如果网略出现问题,此时协调者和参与者无法通信,这种情况下参与者会进行事务提交,必然会出现事务不一致情况。

这里预留一个思考题,三阶段中的第一阶段CanCommit中参与者究竟做了什么事情、如何确认自己是否可以顺利执行事务呢?

以上这些理论在网上很容易能找到,不过想找到这么全的应该不多。遗憾的是就算这些理论都理解了,真正遇到分布式事务需要处理的时候也不一定能处理好,或者说很可能是处理不好的。但是如果找到或者学习接触到了具体方案的实现,回头再结合这些理论不仅能加深对这些理论的理解更能明白实现方案的依据。
推荐几个好用的可以解决分布式事务的框架,将来有时间把这些框架的使用实例分享出来。如下:

1.  TX-LCN分布式事务框架 : http://www.txlcn.org/zh-cn/index.html
2.  Atomikos<部分场景使用是收费的> : https://www.atomikos.com/Main/WebHome
3.  Seata :http://seata.io/zh-cn/

以上,如果有朋友发现我写的有问题,烦劳您告诉我修改调整。感谢!