文章插图
相比较 2PC 而言 , 3PC 对于协调者(Coordinator)和参与者(Participant)都设置了超时时间,解决了参与者在长时间无法与协调者节点通讯(协调者挂掉了)的情况下,无法释放资源的问题,因为参与者自身拥有超时机制会在超时后,自动进行本地 commit 从而进行释放资源 。而这种机制也侧面降低了整个事务的阻塞时间和范围 。
另外 , 通过 CanCommit、PreCommit、DoCommit 三个阶段的设计,相较于 2PC 而言,多设置了一个缓冲阶段保证了在最后提交阶段之前各参与节点的状态是一致的 。
3PC 的缺点:
3PC 在去除阻塞的同时也引入了新的问题,那就是参与者接收到 precommit 消息后 , 如果出现网络分区 , 此时协调者所在的节点和参与者无法进行正常的网络通信,在这种情况下,该参与者依然会进行事务的提交 , 这必然出现数据的不一致性 。
5 补偿事务(TCC)TCC 与 2PC、3PC 一样,只是分布式事务的一种实现方案 。
5.1 TCC 原理:
TCC(Try-Confirm-Cancel)又称补偿事务 。其核心思想是:” 针对每个操作都要注册一个与其对应的确认和补偿(撤销操作)” 。它分为三个操作:
- Try 阶段:主要是对业务系统做检测及资源预留,比如说冻结库存 。
- Confirm 阶段:确认执行业务操作 。
- Cancel 阶段:取消执行业务操作 。
而不足之处则在于对应用的侵入性非常强,业务逻辑的每个分支都需要实现 try、confirm、cancel 三个操作 。此外,其实现难度也比较大,需要按照网络状态、系统故障等不同的失败原因实现不同的回滚策略 。为了满足一致性的要求,confirm 和 cancel 接口还必须实现幂等 。
TCC 的具体原理图如下:
文章插图
5.2 注意事项:
1. 业务操作分两阶段完成:
接入 TCC 前,业务操作只需要一步就能完成,但是在接入 TCC 之后,需要考虑如何将其分成 2 阶段完成,把资源的检查和预留放在一阶段的 Try 操作中进行,把真正的业务操作的执行放在二阶段的 Confirm 操作中进行;
TCC 服务要保证第一阶段 Try 操作成功之后,二阶段 Confirm 操作一定能成功;
文章插图
2. 允许空回滚;
事务协调器在调用 TCC 服务的一阶段 Try 操作时,可能会出现因为丢包而导致的网络超时,此时事务协调器会触发二阶段回滚,调用 TCC 服务的 Cancel 操作;
TCC 服务在未收到 Try 请求的情况下收到 Cancel 请求,这种场景被称为空回滚;TCC 服务在实现时应当允许空回滚的执行;
文章插图
3. 防悬挂控制;
事务协调器在调用 TCC 服务的一阶段 Try 操作时,可能会出现因网络拥堵而导致的超时,此时事务协调器会触发二阶段回滚,调用 TCC 服务的 Cancel 操作;在此之后,拥堵在网络上的一阶段 Try 数据包被 TCC 服务收到,出现了二阶段 Cancel 请求比一阶段 Try 请求先执行的情况;
用户在实现 TCC 服务时,应当允许空回滚 , 但是要拒绝执行空回滚之后到来的一阶段 Try 请求;
文章插图
4. 幂等控制:
无论是网络数据包重传 , 还是异常事务的补偿执行,都会导致 TCC 服务的 Try、Confirm 或者 Cancel 操作被重复执行;用户在实现 TCC 服务时,需要考虑幂等控制,即 Try、Confirm、Cancel 执行次和执行多次的业务结果是一样的;
5. 业务数据可见性控制;
TCC 服务的一阶段 Try 操作会做资源的预留 , 在二阶段操作执行之前 , 如果其他事务需要读取被预留的资源数据,那么处于中间状态的业务数据该如何向用户展示,需要业务在实现时考虑清楚;通常的设计原则是 “宁可不展示、少展示,也不多展示、错展示”;
推荐阅读
- Spring事务超时到底是怎么回事?
- 在Linux服务器上部署容器化的分布式缓存系统
- MySQL 事务死锁问题排查
- 四大事务所是哪四大 会计四大事务所是哪四大
- 数据复制:构建大规模分布式系统的关键组成部分
- 分布式架构和微服务架构的区别
- 分布式锁的三种实现!
- Java与MySQL的并发访问冲突:锁与事务
- 职场求生指南:事务与人际关系,究竟该专攻哪个?
- Spring Boot项目业务代码中使用@Transactional事务失效踩坑点总结