分布式事务的思考

背景

随着系统拆的越来越多,目前系统间的调用是越来越多。那么如何保证系统的一致性成了难点

思考

目前常规关于多系统事务来说会考虑分布式事务XA事务

目前XA事务支持的不是特别多 比如EJB容器会支持【jboss】但是对于传统tomcat等容器来说其实不具备原生XA事务能力。

从业界来看使用atomikos来实现分布式XA事务

Atomikos 是一个为Java平台提供增值服务的并且开源类事务管理器。

Atomikos TransactionsEssentials 是一个为Java平台提供增值服务的并且开源类事务管理器,以下是包括在这个开源版本中的一些功能:

l 全面崩溃 / 重启恢复

l 兼容标准的SUN公司JTA API

l 嵌套事务

l 为XA和非XA提供内置的JDBC适配器

那么我们来看下常规意义上分布式事务的实现

2PC

2PC(tow phase commit)两阶段提交 顾名思义它分成两个阶段,先由一方进行提议(propose)并收集其他节点的反馈(vote),再根据反馈决定提交(commit)或中止(abort)事务。我们将提议的节点称为协调者(coordinator),其他参与决议节点称为参与者(participants, 或cohorts):

当协调者接收到所有的参与者的反馈之后,开始进入事务提交阶段。如果所有参与者都返回 YES,那就发送 COMMIT 请求,如果有一个人返回 NO,那就返送 rollback 请求。

准备阶段

1)协调者节点向所有参与者节点询问是否可以执行提交操作 (vote),并开始等待各参与者节点的响应。

2)参与者节点执行询问发起为止的所有事务操作,并将 Undo 信息和 Redo 信息写入日志。(注意:若成功这里其实每个参与者已经执行了事务操作)

3)各参与者节点响应协调者节点发起的询问。如果参与者节点的事务操作实际执行成功,则它返回一个” 同意” 消息;如果参与者节点的事务操作实际执行失败,则它返回一个” 中止” 消息。

提交阶段

1)协调者节点向所有参与者节点发出”正式提交 (commit)” 的请求。

2)参与者节点正式完成操作,并释放在整个事务期间内占用的资源。

3)参与者节点向协调者节点发送” 完成” 消息。

4)协调者节点受到所有参与者节点反馈的” 完成” 消息后,完成事务。

dab074f5bea219ce3e67f3596b81533a8e9.jpg

协调者在询问阶段参与者将执行事务操作【也就是锁定资源】这种情况下对于协调者的稳定性提出了要求 如果出现挂机那么就容易出现一些不一致性

3PC

与两阶段提交不同的是,三阶段提交有两个改动点。

1、引入超时机制。同时在协调者和参与者中都引入超时机制。
2、在第一阶段和第二阶段中插入一个准备阶段。保证了在最后提交阶段之前各参与节点的状态是一致的。

也就是说,除了引入超时机制之外,3PC 把 2PC 的准备阶段再次一分为二,这样三阶段提交就有CanCommit【prepare】、PreCommit、DoCommit三个阶段。

45dc46d7630567c77252126b2b949dbfa1b.jpg

TCC

和上述两个在db层次的协议不同

上述两种方案对于db资源来说将会出现一些问题 整个事务的持续时间取决于最长的事务。如果某个事务时间太长 那么导致资源被锁定时间太长。这样的话将严重影响系统的吞吐率。

在一个长事务( long-running )中 ,一个由两台服务器一起参与的事务,服务器 A 发起事务,服务器 B 参与事务,B 的事务需要人工参与,所以处理时间可能很长。如果按照 ACID 的原则,要保持事务的隔离性、一致性,服务器 A 中发起的事务中使用到的事务资源将会被锁定,不允许其他应用访问到事务过程中的中间结果,直到整个事务被提交或者回滚。这就造成事务 A 中的资源被长时间锁定,系统的可用性将不可接受。

e04349bc30ac3893beaf4051731bc238ffe.jpg

这个角度来看对于系统的编码压力大了许多 要求所有的参与者关于分布事务的实现完成TCC三个接口 同时保证幂等。因此通常来说使用较少

1e66b09e668b5920b7defc2f1dd3f06a4ca.jpg

补偿

补偿相对于tcc机制来说减少了许多工作量。一般对于接口定义一个反向冲正操作

64d481372ba5243c2a4cdd7ebcb42f9fc98.jpg

通常在分布式环境中定义多个接口方便进行反向冲正

a23f6e7a8f5ff4c6a77f3cc6cf58b01f2fe.jpg

事务消息

通过异步的形式将对应的消息发送【要求被调用方的处理结果不影响调用方的结果】

5b167c4cce6a1eb756ba2d0e3f17c7452fe.jpg

同时为了完成支持重复调用 必须被调用接口支持幂等性要求

e41b8501eb1da0678d45624d0f37879b5bb.jpg

对于目前来说除了写到db中还存在其他方案【典型就是事务消息】

f52c9a3c34726361574d5b941cee4ac4de6.jpg