事务模式
聚合根的本地事务解析
在介绍分布式事务具体之前,先剖析一下 phoenix 中实体聚合根的本地事务。
在Phoenix当中,实体聚合根是最小的逻辑处理单元,一个Phoenix集群会有N多个实体聚合根对象,每个实体聚合根对象在处理消息时都满足事务中ACID
的特性,下面解析一下实体聚合根对ACID
的支持能力。
特性 | 支持级别 | 实现原理 |
---|---|---|
原子性(Atomicity) | 支持 | 实体聚合根处理消息修改多个状态时,可以保证要么全部成功要么全部失败。 |
一致性(Consistency) | 支持 | 实体聚合根处理消息是有序处理的,对于每个消息处理时,状态是线性一致的。 |
隔离性(Isolation) | 支持 | 实体聚合根处理消息是有序处理的,隔离级别是最高(串行化)。 |
持久性(Durability) | 支持 | 实体聚合根的状态依赖EventStore存储,依赖EventSouring技术恢复。 |
分布式事务产生的背景
在Phoenix当中,业务是实体聚合根
处理的,实体聚合根都有一个唯一id标识(聚合根id),一个实体聚合根内部处理消息
时满足事务的ACID
特性。但业务系统使用Phoenix开发服务时,会对业务做水平
和服务化
拆分成不同的聚合根,如果一个业务请求需要多个聚合根一起完成的话,就引出了分布式事务。
实体聚合根水平拆分
在使用Phoenix框架时,为了追求并发粒度来承担更大的业务体量,会对一个聚合根做水平
拆分,通常一个聚合根类通过不同的聚合根id
来生成不同的聚合根对象
,那么不同的聚合根对象运行时会在不同的节点当中。如下图所示,一个账户聚合根通过账户id来生成了N个聚合根对象,这些聚合根对象运行在不同的节点当中,如果发起账户1
对账户2
的转账请求,则会涉及到分布式事务场景。
实际上
账户1
向账户3
转账也是一个分布式事务,虽然这两个实体聚合根对象在一个节点上,但是phoenix是无服务化的思想,一切都以聚合根隔离。
实体聚合根服务化拆分
在使用Phoenix框架时,会进行DDD领 域设计出不同类型的聚合根
,比如商品购物业务场景可以划分为商品仓储
和资金账户
两类聚合根,不同类别聚合根会协作完成购物的流程,这样则会涉及分布式事务的场景。
分布式事务理论基础
XA协议
XA
协议是一个基于数据库的分布式事务协议,其分为两部分:事务管理器和本地资源管理器。事务管理器作为一个全局的调度者,负责对各个本地资源管理器进行统一提交或者回滚。二阶提交协议(2PC)和三阶提交协议(3PC)就是根据此协议衍生出来而来。如今Oracle、Mysql等数据库均已实现了XA接口。
2PC
协议流程图
上边图片源自网络,如有侵权联系删除
实际上无论是2PC
还是3PC
协议都尝试在满足比较强的ACID
特性,但是付出的代价也很高,就是性能很慢,阻塞同步等等。实际上3PC
也存在数据不一致的问题,这里就不再阐述。
XA
协议是站在关系型数据库维度提出的,应用在DB
层面,并且旨在做到对用户透明,ACID
的保障等。现在场景一般习惯在用户层面解决分布式事务问题的话,可以使用TCC
和SAGA
,虽然丧失了一些隔离性和一致性但是可以做到无锁,非阻塞。
TCC协议
TCC(Try-Confirm-Cancel)实际上是服务化的两阶段提交协议,业务开发者需要实现这三个服务接口,第一阶段由业务代码编排来调用 Try 接口进行资源预留,所有参与者的 Try 接口都成功了,事务管理器会提交事务,并调用每个参与者的 Confirm 接口真正提交业务操作,否则调用每个参与者的 Cancel 接口回滚事务。
- Try阶段: 下单时通过Try操作去扣除库存预留资源。
- Confirm阶段: 确认执行业务操作,在只预留的资源基础上,发起购买请求。
- Cancel阶段: 只要涉及到的相关业务中,有一个业务方预留资源未成功,则取消所有业务资源的预留请求。
理论上Confirm阶段和Cancel阶段不允许出现业务型失败,框架实现时要保证幂等,超时重试,超时回滚,空回滚,悬挂等一系列问题,后文会详细介绍Phoenix的实现。
TCC对于ACID的保证:
- 原子性:正常情况下保证。
- 一致性:最终一致性,可能出现A本地事务和B本地事务不一致的情况。
- 隔离性:不保证,在某个时间点会出现一个事务看到另外一个事务的中间结果。
- 持久性:和本地事务一样,只要分布式事务结束,则会被持久化。