分布式事务
背景
在单体应用下无法满足现用业务,需要将应用拆分为多个服务。由于应用拆分为多个服务器后,相当于服务之间的边界更加清晰,并且都能独立运行,但是带来的问题是本来是内部调用,变为远程调用,整体调用链更长了,从而导致调用时间变长,但是总体的吞吐量增加了,同时也引发了其他问题,比如: 链路日志不够完善详细也会导致出现问题定位更加困难;多个服务共同完成一件事,要求必须同时成功或者失败,也就是 事务的问题;
解决方案
2PC 两阶段提交协议(Two-phase commit protocol)
2PC
顾名思义将整个过程分为了以下两个步骤
- 准备阶段 : 业务操作,但是不做事务提交
- 提交/回滚阶段 : 执行事务 提交 或者 回滚 操作
除此之外2PC
还引入 事务协调者 作为管理方去给其他服务下发阶段指令。具体参考下图
缺点
从图中可以明显的发现2PC
以下的几个问题:
- 同步阻塞 : 由于服务进入准备阶段后会锁定资源,从而导致其他请求需要访问同一个资源的时候导致阻塞
- 单点故障 : 如果事务协调者宕机后,那么整个事务就无法执行,导致开启的事务一直在锁定状态
- 数据不一致 : 由于是通过网络请求,就不可避免的出现网络波动或者超时的情况,导致事务提交不一致的问题
优点
- 不侵入业务,可以直接使用数据库的事务使用
分布式数据库的 2PC 改进模型
- 事务协调者变为服务方自己承担,即多个服务会选举出事务协调者,当协调者宕机后会重新选举协调者,避免了单点故障导致的问题
- 使用全局分布式事务ID,避免数据不一致的问题
3PC
相对2PC多了一个阶段
- 询问阶段 : 会去询问服务是否可用,避免不正常的服务参加事务,导致资源锁定
TCC
TCC 分为指代 Try
、Confirm
、Cancel
,也就是业务层面需要写对应的三个方法,主要用于跨数据库、跨服务的业务操作的数据一致性问题。
根据上图可以发现,TCC的每个阶段都是独立的,并不会一直阻塞资源,如果有服务产生失败,只需要调用Cancel
去做撤销操作。
关键点
- 幂等性 : 由于网络调用无法保证请求一定正常到达,所以必须保证三个接口的幂等性
- 空回滚 : 由于网络问题,导致未执行
Try
方法就调用了Cancel
方法,不能因此报错 - 悬挂 : 由于网络问题导致调用
Try
网络阻塞,从而调用Cancel
方法,但是执行完Cancel
方法后网络恢复执行了Try
方法,所以要避免执行Try
方法但是由于事务已经取消了,导致不必要的执行
案例
业务场景,假设你现在有一个电商系统,里面有一个支付订单的场景
整体业务应该是需要保证要么一起成功或者一起失败
Try
Confirm
Cancel
参考连接 :
- https://www.cnblogs.com/jajian/p/10014145.html
- https://juejin.cn/post/6874788280378851335?utm_source=gold_browser_extension#heading-13