分布式事务解决方案
分布式的特点:分布性、对等性、并发性、缺乏全局时钟、故障总会发生
分布式环境下的各种问题:通讯异常、网络分区、成功失败超时三态、节点故障
CAP
在当前的软件架构模式下,有状态服务部署(分布式部署模式下),无法同时保证可用性和一致性,必有取舍。
- 如果追求数据一致性:可以让数据完成后大家再去读取,损失一部分性能换取一致性。
- 如果追求可用性:可以采用异步模式同步数据,只有主机进行存取,从机只负责备份,监控主机,主要切换瞬间也会出现数据丢失问题。
因此互联网行业追求性能选择可用性,通过Base理论解决数据一致性问题。
Base理论
- 基本可用(Basically Available)
- 软状态(Soft State)
- 最终一致性(Eventually Consistent)
强调的是所有数据更新操作在经过一段时间同步后,最终都能达到一个一致状态。
分布式事务:
当下互联网约大部分公司都进行了数据拆分和服务化(SOA),在这种情况下,完成某一个业务功能可能需要横跨多个服务,操作多个数据库。这就涉及分布式事务,用需要操作的资源位于多个服务器上,而应用需要保证对于多个资源服务器的操作,要么全部成功,要么全部失败,本质上来说,分布式事务就是为了保证不同资源服务器的数据一致性。
两阶段提交(2PC)
两阶段提交2PC(Two phase Commit)是指,在分布式系统里,为了保证所有节点在进行事务提交时保持一致性的一种算法。
提交请求(投票)阶段
- 协调者向所有参与者发送prepare请求与事务内容,询问是否可以准备事务提交,并等待参与者的响应。
- 参与者执行事务中包含的操作,并记录undo日志(用于回滚)和redo日志(用于重放),但不真正提交。
有两个改动点: - 参与者向协调者返回事务操作的执行结果,执行成功返回yes,否则返回no。
提交(执行)阶段
分为成功与失败两种情况。
- 若所有参与者都返回yes,说明事务可以提交:
- 协调者向所有参与者发送commit请求。
- 参与者收到commit请求后,将事务真正地提交上去,并释放占用的事务资源,并向协调者返回ack。
- 协调者收到所有参与者的ack消息,事务成功完成。
若有参与者返回no或者超时未返回,说明事务中断,需要回滚:
- 协调者向所有参与者发送rollback请求。
- 参与者收到rollback请求后,根据undo日志回滚到事务执行前的状态,释放占用的事务资源,并向协调者返回ack。
- 协调者收到所有参与者的ack消息,事务回滚完成。
提交成功:
提交失败:
问题:
-
同步阻塞问题。执行过程中,所有参与节点都是事务阻塞型的。当参与者占有公共资源时,其他第三方节点访问公共资源不得不处于阻塞状态。
-
单点故障。由于协调者的重要性,一旦协调者发生故障。参与者会一直阻塞下去。尤其在第二阶段,协调者发生故障,那么所有的参与者还都处于锁定事务资源的状态中,而无法继续完成事务操作。(如果是协调者挂掉,可以重新选举一个协调者,但是无法解决因为协调者宕机导致的参与者处于阻塞状态的问题)
-
数据不一致。在二阶段提交的阶段二中,当协调者向参与者发送commit请求之后,发生了局部网络异常或者在发送commit请求过程中协调者发生了故障,这回导致只有一部分参与者接受到了commit请求。而在这部分参与者接到commit请求之后就会执行commit操作。但是其他部分未接到commit请求的机器则无法执行事务提交。于是整个分布式系统便出现了数据部一致性的现象。
-
二阶段无法解决的问题:协调者再发出commit消息之后宕机,而唯一接收到这条消息的参与者同时也宕机了。那么即使协调者通过选举协议产生了新的协调者,这条事务的状态也是不确定的,没人知道事务是否被已经提交。
二阶段提交存在着诸如同步阻塞、单点问题、脑裂等缺陷,所以,研究者们在二阶段提交的基础上做了改进,提出了三阶段提交。
三阶段提交(3PC)
三阶段提交是二阶段提交的改进版,与两阶段提交不同的是三阶段提交有两个改动点:
- 引入超时机制。同时在协调者和参与者中都引入超时机制。
- 在第一阶段和第二阶段中插入一个准备阶段,保证了在最后提交阶段之前各参与节点的状态是一致的。3PC把2PC的准备阶段再次一分为二,这样三阶段提交就有CanCommit、PreCommit、DoCommit三个阶段。
3PC比2PC效率低,一般不采用,这里只做了解。
解决方案
JTA
分布式事务java版本接口规范(把xa接口进行了java版本扩展,实现本地化),因此很多服务厂商依托于java实现JTA接口。
- jboss——分布式事务解决
- weblogic——分布式事务结构
- tomcat——没有实现jta接口提供数据一致性解决方案
- undertow——没有实现jta接口提供数据一致性解决方案
Atomikos
tomcat可以引入Atomikos的Jar包实现分布式事务
Lcn
事务注册原理:
- 事务发起者:先创建一个事务组
- 其它业务:在事务组中注册子事务
- 通知大家统一提交
特点:
- 代码嵌入性低
- 仅限于本地存在连接对象且可能连接对象控制事务的模块
- 事务提交与回滚由本地事务方控制,对于数据一致性上有较高的保障
缺点:
- 代理连接需要随事务发起方一共释放连接,增加连接占用时间
Tcc
业务补偿机制、日志方式进行补偿
try {
A + 100;
B - 100;
System.out.println();
} catch {
//补偿
A - 100;
B + 100
}
Try——业务处理
Confirm——确认
Cancel——回滚
最终消息一致性
使用消息队列进行异步操作达到最终一致性。
- mq发送一条消息(半消息)
- 通知消息发送成功
- 执行本在事务
- 提交或回滚
- 执行状态回查
- 查询本地事务状态
- 再次提交或回滚