最终一致性2PC范式,提供多聚合根之间交互事务的抽象接口。任何基于cqrs + eda 实现多聚合根最终一致性的框架,都可基于此接口进行实现,以达到提高开发效率的目的。
由于事务控制也在业务端,所以此处的 2PC 概念,可以等效于 TCC 概念;目前不支持 Timeout 隐式 Cancel。
dotnet add package Eventual2PC 2pc(two-phase commit protocol)是非常经典的强一致性、中心化的原子提交协议。中心化是指协议中有两类节点:一个中心化协调者节点(coordinator)和N个参与者节点(participant、cohort)。
协议的每一次事务提交分为两个阶段:
-
第一阶段,协调者询问所有的参与者是否可以提交事务(请参与者投票),所有参与者向协调者投票。
-
第二阶段,协调者根据所有参与者的投票结果做出是否事务可以全局提交的决定,并通知所有的参与者执行该决定。
在一个两阶段提交流程中,参与者不能改变自己的投票结果。两阶段提交协议的可以全局提交的前提是所有的参与者都同意提交事务,只要有一个参与者投票选择放弃(abort)事务,则事务必须被放弃。
文献参考:https://www.the-paper-trail.org/post/2008-11-27-consensus-protocols-two-phase-commit/
TCC(Try-Confirm-Cancel)又称补偿事务。其核心思想是:"针对每个操作都要注册一个与其对应的确认和补偿(撤销操作)"。它分为三个操作:
-
Try阶段:主要是对业务系统做检测及资源预留。
-
Confirm阶段:确认执行业务操作。
-
Cancel阶段:取消执行业务操作。
TCC事务的处理流程与2PC两阶段提交类似,不过2PC通常都是在跨库的DB层面,而TCC本质上就是一个应用层面的2PC,需要通过业务逻辑来实现。这种分布式事务的实现方式的优势在于,可以让应用自己定义数据库操作的粒度,使得降低锁冲突、提高吞吐量成为可能。
为了满足一致性的要求,confirm和cancel接口还必须实现幂等。
文献参考: https://www.enterpriseintegrationpatterns.com/patterns/conversation/TryConfirmCancel.html
-
Initiator: 事务发起方,它是聚合根,用于维护事务状态;如果本身也参与当前事务,那么在发起事务时的业务校验等效于PreCommit,在处理TransactionCompleted事件时修改自身状态等效于Commit -
ProcessManager: CQRS中的概念,作为事务相关消息路由的角色,用于协调Participant -
Coordinator: 事务协调者,是Initiator+ProcessManager的概念总和 -
Participant: 事务参与方(仅针对被修改的聚合根,因为新增不会产生业务失败问题;若需要新增的聚合根参与事务,可以在ProcessManager响应AllParticipantPreCommitSucceed事件时发送命令消息),它是聚合根,负责接受PreCommit、Commit、Rollback以处理自身业务 -
Preparation:Participant的事务准备,表示参与事务的业务修改行为,一个事务准备可以用于不同事务 -
Transaction: 2PC事务,可以只是一个标识ID(通常使用TransactionStarted事件的ID),也可以使用代表事务的聚合根(如银行转账的转账事务聚合根)
-
AddPreCommitSucceedParticipant: 添加预提交成功的参与方 -
AddPreCommitFailedParticipant: 添加预提交失败的参与方 -
AddCommittedParticipant: 添加已提交的参与方 -
AddRolledbackParticipant: 添加已回滚的参与方
-
TransactionStarted: 事务已发起事件 -
PreCommitSucceedParticipantAdded: 预提交成功的参与者已添加事件 -
PreCommitFailedParticipantAdded: 预提交失败的参与者已添加事件 -
AllParticipantPreCommitSucceed: 所有参与者预提交已成功事件 -
AnyParticipantPreCommitFailed: 任意一个参与者预提交已失败事件 -
CommittedParticipantAdded: 已提交的参与者已添加事件 -
RolledbackParticipantAdded: 已回滚的参与者已添加事件 -
TransactionCompleted: 事务已完成事件,并包含是否事务已提交的状态
-
PreCommit: 预提交 -
Commit: 提交 -
Rollback: 回滚
-
PreCommitSucceed: 预提交已成功事件 -
PreCommitFailed: 预提交已失败事件(或领域异常消息) -
Committed: 已提交事件 -
Rolledback: 已回滚事件
-
一个聚合根,可以同时扮演
Initiator和Transaction的角色,如银行转账事务聚合根 -
一个聚合根,可以同时扮演事务A中的
Participant和事务B的Initiator -
Initiator的聚合根实例,发起事务时,必须存在至少一个Participant,且不能把自己作为Participant;如果自己参与事务中,则通过发起事务都位置进行业务校验,在处理TransactionCompleted事件时提交业务修改 -
Initiator的聚合根实例,如果处于事务A中,那么将不允许作为事务B的Participant,直到事务A结束,才允许 -
Initiator的聚合根实例,仅允许发起一个事务,只有事务完成后,才可以发起其他事务;此处的事务完成,以是否发布TransactionCompleted事件为准 -
Participant参与事务的业务修改行为有多少个,对应定义多少个Preparation,与参与的事务数无关 -
Participant的聚合根实例,允许同时参与多个不同的事务;也可以通过业务代码,在PreCommit时,判断是否存在其他类型的Preparation来阻止当前Preparation的PreCommit操作 -
Initiator和Participant的命令处理都必须支持幂等
-
Initiator发布TransactionStarted事件 -
ProcessManager响应TransactionStarted事件,并发送PreCommit命令 -
Participant处理命令PreCommit-
如果成功,则发布
PreCommitSucceed事件; -
如果失败,则发布
PreCommitFailed事件(或领域异常)。
-
-
ProcessManager响应PreCommitSucceed,并发送AddPreCommitSucceedParticipant命令 -
ProcessManager响应PreCommitFailed,并发送AddPreCommitFailedParticipant命令 -
Initiator处理命令AddPreCommitSucceedParticipant,发布PreCommitSucceedParticipantAdded事件-
如果所有
Participant的PreCommit都已处理完成且都成功,则再发布AllParticipantPreCommitSucceed事件; -
如果已处理完成,但存在失败,则再发布
AnyParticipantPreCommitFailed事件。
-
-
Initiator处理命令AddPreCommitFailedParticipant,发布PreCommitFailedParticipantAdded事件-
如果所有
Participant的PreCommit都已处理完成,则发布AnyParticipantPreCommitFailed事件; -
如果已处理完成,且都失败,则再发布
TransactionCompleted事件。
-
-
ProcessManager响应AllParticipantPreCommitSucceed,并发送Commit命令 -
ProcessManager响应AnyParticipantPreCommitFailed,并发送Rollback命令 -
Participant处理命令Commit,并发布Committed事件 -
Participant处理命令Rollback,并发布Rolledback事件 -
ProcessManager响应Committed,并发送AddCommittedParticipant命令 -
ProcessManager响应Rolledback,并发送AddRolledbackParticipant命令 -
Initiator处理命令AddCommittedParticipant,发布CommittedParticipantAdded事件- 如果所有
Participant的Commit都已处理完成,则再发布TransactionCompleted事件。
- 如果所有
-
Initiator处理命令AddRolledbackParticipant,发布RolledbackParticipantAdded事件- 如果所有
Participant的Rolledback都已处理完成,则再发布TransactionCompleted事件。
- 如果所有
-
1)
ITransactionInitiator接口增加属性CurrentTransactionId、CurrentTransactionType -
2)增加事务流转过程中产生的
Command的接口定义
- 移除异常类
UnknownTransactionPreparationException
- 移除
TransactionParticipantInfo的方法ValidateParticipantMustNotExists,是否抛出异常,由使用方决定
- 初始版本
非常感谢 ENode群,热心群友提出的各种异议,以及 ENode 的作者 汤雪华 阐述2PC概念、ENode设计理念,提供了宝贵的意见。


