参考文章:
https://blog.csdn.net/congyihao/article/details/70195154
https://blog.csdn.net/mine_song/article/details/64118963
https://www.cnblogs.com/savorboard/p/distributed-system-transaction-consistency.html
柔性事务 vs. 刚性事务
刚性事务是指严格遵循ACID原则的事务, 例如单机环境下的数据库事务.
柔性事务是指遵循BASE理论的事务, 通常用在分布式环境中, 常见的实现方式有: 两阶段提交(2PC), TCC补偿型提交, 基于消息的异步确保型, 最大努力通知型.
最佳实践
先上结论, 再分别介绍分布式事务的各种实现方式.
如果业务场景需要强一致性, 那么尽量避免将它们放在不同服务中, 也就是尽量使用本地事务, 避免使用强一致性的分布式事务.
如果业务场景能够接受最终一致性, 那么最好是使用基于消息的最终一致性的方案(异步确保型)来解决.
如果业务场景需要强一致性, 并且只能够进行分布式服务部署, 那么最好是使用TCC方案而不是2PC方案来解决.
两阶段提交(2PC)
两阶段提交(Two Phase Commit, 2PC), 具有强一致性, 是CP系统的一种典型实现.
两阶段提交, 常见的标准是XA, JTA等. 例如Oracle的数据库支持XA.
缺点
两阶段提交中的第二阶段, 协调者需要等待所有参与者发出yes请求, 或者一个参与者发出no请求后, 才能执行提交或者中断操作. 这会造成长时间同时锁住多个资源, 造成性能瓶颈, 如果参与者有一个耗时长的操作, 性能损耗会更明显.
实现复杂, 不利于系统的扩展, 不推荐.
TCC (Try-Confirm-Cancle)
TCC, 是基于补偿型事务的AP系统的一种实现, 具有最终一致性.
优点
对比与前面提到的两阶段提交法, 有两大优势:
TCC能够对分布式事务中的各个资源进行分别锁定, 分别提交与释放, 例如, 假设有AB两个操作, 假设A操作耗时短, 那么A就能较快的完成自身的try-confirm-cancel流程, 释放资源. 无需等待B操作. 如果事后出现问题, 追加执行补偿性事务即可.
TCC是绑定在各个子业务上的(除了cancle中的全局回滚操作), 也就是各服务之间可以在一定程度上”异步并行”执行.
注意事项
事务管理器(协调器)这个节点必须以带同步复制语义的高可用集群(HAC)方式部署.
事务管理器(协调器)还需要使用多数派算法来避免集群发生脑裂问题.
适用场景
严格一致性
执行时间短
实时性要求高
举例: 红包, 收付款业务.
异步确保型
通过将一系列同步的事务操作变为基于消息执行的异步操作, 避免了分布式事务中的同步阻塞操作的影响.
这个方案真正实现了两个服务的解耦, 解耦的关键就是异步消息和补偿性事务.
这里以一个例子作为讲解:
执行步骤如下:
MQ发送方发送远程事务消息到MQ Server;
MQ Server给予响应, 表明事务消息已成功到达MQ Server.
MQ发送方Commit本地事务.
若本地事务Commit成功, 则通知MQ Server允许对应事务消息被消费; 若本地事务失败, 则通知MQ Server对应事务消息应被丢弃.
若MQ发送方超时未对MQ Server作出本地事务执行状态的反馈, 那么需要MQ Servfer向MQ发送方主动回查事务状态, 以决定事务消息是否能被消费.
当得知本地事务执行成功时, MQ Server允许MQ订阅方消费本条事务消息.
需要额外说明的一点, 就是事务消息投递到MQ订阅方后, 并不一定能够成功执行. 需要MQ订阅方主动给予消费反馈(ack)
如果MQ订阅方执行远程事务成功, 则给予消费成功的ack, 那么MQ Server可以安全将事务消息移除;
如果执行失败, MQ Server需要对消息重新投递, 直至消费成功.
注意事项
消息中间件在系统中扮演一个重要的角色, 所有的事务消息都需要通过它来传达, 所以消息中间件也需要支持 HAC 来确保事务消息不丢失.
根据业务逻辑的具体实现不同,还可能需要对消息中间件增加消息不重复, 不乱序等其它要求.
适用场景
执行周期较长
实时性要求不高
例如:
跨行转账/汇款业务(两个服务分别在不同的银行中)
退货/退款业务
财务, 账单统计业务(先发送到消息中间件, 然后进行批量记账)
最大努力通知型
这是分布式事务中要求最低的一种, 也可以通过消息中间件实现, 与前面异步确保型操作不同的一点是, 在消息由MQ Server投递到消费者之后, 允许在达到最大重试次数之后正常结束事务.
适用场景
交易结果消息的通知等.
小结
不管是同步事务中的事务管理器(协调者), 还是异步事务中使用的消息中间件,若要达到一致性保证,都需要使用带有同步复制语义的 HAC 提供的高可用和高可靠特性,这些都是以性能为代价的,无疑成为了SOA 架构中的典型性能瓶颈之一.