文档参考:书名:《企业it架构转型之道》-钟华
1. 传统分布式事务
上面提到数据在按照业务领域(用户中心、交易中心)的不同被拆分到不同的数据库后,在某些业务场景(比如订单创建)下,就必然会出现同一个事务上下文中,需要协调多个资源(数据库)以保证业务的事务一致性,对于这样的场景,业界早就有基于两阶段提交方式实现的分布式事务.
两阶段提交协议包含了两个阶段:第一阶段(也称准备阶段)和第二阶段(也称提交阶段)。一个描述两阶段提交很好的类比是典型的结婚仪式,每个参与者(结婚典礼中的新郎和新娘)都必须服从安排,在正式步入婚姻生活之前说“我愿意”。一旦其中一位“参与者”在做出承诺前的最后一刻反悔,则这场婚礼就演变为一个悲剧。两阶段提交之于此的结果也成立,虽然不具备如婚礼上那么大的破坏性。
当commit请求从客户端向事务管理器发出,事务管理器开始两阶段提交过程。在第一阶段,所有的资源被轮询到,问它们是否准备好了提交作业。每个参与者可能回答“就绪”(READY)、“只读”(READ_ONLY)或“未准备好”(NOT_READY)。如果有任意一个参与者在第一阶段响应“未准备好”(NOT_READY),则整个事务回滚。如果所有参与者都回答“就绪”(READY),那这些资源就在第二阶段提交。回答“只读”(READ_ONLY)的资源,则在协议的第二阶段处理中被排除掉。
两阶段提交协议要求分布式事务参与者实现一个特别的“准备”操作,无论在资源管理器(如数据库)还是在业务服务中实现该操作都存在效率与复杂性的挑战。因此,两阶段提交协议有一个重要的优化,称为“最末参与者优化”(Last Participant Optimization, LPO),允许两阶段提交协议中有一个参与者不实现“准备”操作(称为单阶段参与者)。最末参与者优化的原理如图所示。
从图中可见,LPO中单阶段参与者不需要实现准备操作,只需要提供标准的提交操作即可。分布式事务协调者必须等其余两阶段参与者都准备好之后,再请求单阶段参与者提交,单阶段参与者的提交结果将决定整个分布式事务的结果。本质上,LPO是将最后一个参与者的准备操作与提交/放弃操作合并成一个提交操作。
X/Open组织为基于两阶段协议的分布式事务处理系统提出了标准的系统参考模型(X/Open事务模型)以及不同组件间与事务协调相关的接口,使不同厂商的产品能够互操作。X/Open事务模型如图所示:
从图中可以看出,X/Open模型定义了两个标准接口:TX接口用于应用程序向事务管理器发起事务、提交事务和回滚事务(即确定事务的边界和结果); XA接口形成了事务管理器和资源管理器之间的通信桥梁,用于事务管理器将资源管理器(如数据库、消息队列等)加入事务、并控制两阶段提交。
事务管理器一般由专门的中间件提供,或者在应用服务器中作为一个重要的组件提供。资源管理器如数据库、消息队列等产品一般也会提供对XA接口的支持,通过使用符合X/Open标准的分布式事务处理,能够简化分布式事务类应用的开发。
图中可见,两阶段提交协议的关键在于“预备”操作。分布式事务协调者在第一阶段通过对所有的分布式事务参与者请求“预备”操作,达成关于分布式事务一致性的共识。 分布式事务参与者在预备阶段必须完成所有的约束检查,并且确保后续提交或放弃时所需要的数据已持久化。在第二队段,分布式事务协调者根据之前达到的提交或放弃的共识,请求所有的分布式事务参与者完成相应的操作。很显然,在提交事务的过程中需要在多个资源节点之间进行协调,而各节点对锁资源的释放必须等到事务最终提交时,这样,比起一阶段提交,两阶段提交在执行同样的事务时会消耗更多时间:
❑单机锁=时间消耗(微秒级)
❑跨多机的锁=时间消耗(毫秒级)= 1000倍单机时间消耗
事务执行时间的延长意味着锁资源发生冲突的概率增加,当事务的并发量达到一定数量的时候,就会出现大量事务积压甚至出现死锁,系统性能和处理吞吐率就会严重下滑,也就是系统处理的吞吐率与资源上的时间消耗成反比(参考阿姆达尔定理)。这就是为什么今天在互联网应用场景中鲜有人会选择这样传统的分布式事务方式,而选择柔性事务处理业务事务的主要原因。