分布式事务-TCC异常之悬挂
分布式事务-TCC异常之悬挂
在分布式事务处理中,TCC(Try-Confirm-Cancel)模式是一种常见的解决方案。然而,在实际应用中,这种模式可能会遇到一种特殊的异常情况——悬挂问题。本文将详细介绍TCC悬挂问题的背景、产生原因、具体场景以及解决方案。
在TCC事务模式下,我们通过一个事务协调器来管理多个事务,每个事务先执行try方法。当所有事务参与者的try方法执行成功,就执行confirm方法完成真正逻辑的执行,一旦任意一个事务参与者出现异常,就通过cancel接口触发事务回滚,释放Try阶段占用的资源。
很显然,这是一个最终一致性的实现方案,因此当Try执行成功,就必须确保Confirm执行成功。当Try执行失败,就必须确保Cancel实现资源释放。而面试题中提到悬挂问题,指的是TCC执行Try接口出现网络超时时候,使得TCC触发Cancel接口回滚,但可能在回滚之后,这个超时的Try接口才被真正执行,也就导致Cancel接口比Try接口先执行。从而造成Try接口预留的资源一直无法释放,这种情况就是悬挂。以上就是TCC悬挂问题的背景,它确实是每个成熟的高级开发必须要了解的细节。因为有可能会造成比较严重的生产事故。
概念
TCC悬挂指的是在分布式事务执行过程中,Try操作由于某些原因(如网络延迟、服务故障等)被延迟处理,而此时事务协调器已经判定该事务执行失败并触发了Cancel操作,并且Cancel操作正常执行完毕。之后,被延迟的Try操作才到达并执行,由于Cancel操作已经完成,这个延迟的Try操作就没有了对应的Confirm或Cancel操作与之匹配,导致资源被不合理地锁定或占用,这就是TCC悬挂问题。
产生原因
- 网络延迟:在分布式系统中,各个服务节点之间通过网络进行通信。如果网络状况不佳,Try请求可能会在传输过程中出现延迟,使得其到达目标服务的时间晚于事务协调器触发Cancel操作的时间。
- 服务过载:目标服务可能由于负载过高,无法及时处理接收到的Try请求,导致处理时间过长,从而出现Try操作延迟执行的情况。当事务协调器因为长时间未收到Try操作的响应而触发Cancel操作后,延迟的Try操作才开始执行。
- 事务协调器误判:事务协调器可能由于自身的逻辑错误或配置不合理,过早地判定Try操作执行失败并触发Cancel操作,而实际上Try请求还在传输或等待处理,随后延迟的Try操作就会造成悬挂问题。
示例场景
假设一个电商系统中有一个订单创建的分布式事务,涉及库存服务和账户服务。当用户下单时,会先调用库存服务的Try方法冻结相应的商品库存,再调用账户服务的Try方法冻结用户账户中的资金。
- 由于网络延迟,库存服务的Try请求在传输过程中被延迟。
- 事务协调器在等待一段时间后,没有收到库存服务的Try响应,判定该事务失败,于是触发了库存服务和账户服务的Cancel操作。
- 账户服务和库存服务执行Cancel操作,释放之前可能已经冻结的资源(虽然库存服务实际上还未执行Try操作)。
- 之后,被延迟的库存服务的Try请求到达并执行,冻结了商品库存,但此时由于Cancel操作已经完成,后续不会再有对应的Confirm或Cancel操作来处理这个冻结的库存,从而导致库存资源被悬挂。
解决方案
- 请求超时控制:在发起Try请求时,设置合理的超时时间。如果在规定时间内没有收到响应,要进行相应的处理,避免事务协调器过早地触发Cancel操作。同时,对于延迟到达的Try请求,可以根据其到达时间进行判断,如果超过了合理的时间范围,可以直接拒绝执行,避免悬挂问题的产生。
- 状态记录与检查:在每个服务中记录事务的执行状态,包括Try、Confirm和Cancel操作的执行情况。在执行Try操作前,先检查当前事务的状态,如果发现Cancel操作已经执行过,就不再执行Try操作,从而避免悬挂问题。
- 引入补偿机制:当检测到悬挂问题发生时,可以设计相应的补偿机制来释放被不合理占用的资源。例如,在上述电商系统的库存服务中,如果发现出现了悬挂问题,可以手动或自动地释放被冻结的库存,确保资源的正常使用。
此外,实现幂等性也是解决悬挂问题的关键。Try、Confirm和Cancel操作都应设计成幂等的,即无论操作执行多少次,结果都是相同的,这有助于在分布式系统中处理网络重传或操作重试等情况,保证系统的最终一致性。