liuyangming / ByteTCC

ByteTCC is a distributed transaction manager based on the TCC(Try/Confirm/Cancel) mechanism. It’s compatible with the JTA specification. User guide: https://github.com/liuyangming/ByteTCC/wiki
https://www.bytesoft.org/
GNU Lesser General Public License v3.0
2.9k stars 911 forks source link

框架防悬挂/幂等/空回滚如何处理的? #144

Open menghuan123 opened 2 years ago

menghuan123 commented 2 years ago

框架防悬挂/幂等/空回滚如何处理的?

liuyangming commented 2 years ago

你问题中悬挂、空回滚并非业界技术规范定义的专有术语,因此,我尝试就事务管理器可能遇到的几个问题做一下解释,如果没有涉及你的疑问,请进一步说明。

-- 悬挂? i. 问题描述A服务向B服务发起业务请求,该请求因网络阻塞等原因超时,此时A服务TM随即发起回滚。在A服务TM将全局事务回滚完毕后,B服务又收到了A先前发出的请求并执行。 解决方案:B服务仍然会执行且该业务本地事务仍然会被byteTCC提交。后续每个一段间隔的定时程序中,byteTCC会检查每个节点(比如B服务)上的分支事务:按xid查询其上一级传播节点(比如A服务),检查该xid事务是否仍然生效(是否存在,若存在是否已完成)。如果上一级节点不存在或者已完成,则说明本节点尚未完成的分支事务是在全局事务之外提交的,byteTCC会将对应服务的业务方法执行反向逻辑进行回撤。 说明事项: a) byteTCC并未在B服务收到请求时判断是否有效。原因是此时判断会给绝大部分正常的请求增加处理逻辑而造成性能低下。 b) B服务可能会被A服务调用多次,其事务分支中可能存在Try阶段成功且Confirm/Cancel阶段也生效的业务。bytetCC不会回撤这部分已生效的业务。实际上,如果之前分支信息仍然存在,byteTCC检测到当前分支事务已经进入commit/rollback阶段,则会将该Try阶段延迟请求的本地事务直接rollback,从而避免先commit后cancel回撤,精简事务逻辑。

ii. 幂等 相关说明见用户指南中“四、可补偿型业务服务的幂等性说明”章节的说明。

-- 空回滚? iii. 问题描述A服务向B服务发起业务请求,该请求因网络阻塞等原因超时,此时A服务TM随即发起回滚。A服务TM回滚时会向B服务TM发送rollback请求,但实际上B服务节点并没有对应分支事务信息。 解决方案:B服务TM(byteTCC)根据上一级TM(A服务TM)发送过来的xid,检索自己当前生效的事务,发现并没有找到指定事务,会发送一个NOTA的响应码,标识该分支并没有指定的事务;上一届TM(A服务TM)收到相应后即明白B服务并未参与全局事务,并将分支其标示为完成(方向既不是commit也不是rollback,但完成了)。 说明事项: a) 倘若后续B服务又收到了请求,则处理逻辑见第一个场景。

menghuan123 commented 2 years ago

( byteTCC并未在B服务收到请求时判断是否有效。原因是此时判断会给绝大部分正常的请求增加处理逻辑而造成性能低下)这里的描述有点不太明白,空回滚这里处理会检索当前生效的事务了,所以正常的请求也会有检索操作吧,这里判断会增加的处理逻辑性能消耗在哪里呢?

liuyangming commented 2 years ago

问题描述:A服务向B服务发起业务请求,该请求因网络阻塞等原因超时,此时A服务TM随即发起回滚。在A服务TM将全局事务回滚完毕后,B服务又收到了A先前发出的请求并执行。

上述这个场景存在多少概率呢?实际上,以我的既往经验(本人曾在一款商业应用服务器中间件中实现基于XA/2PC的分布式事务管理器)来看,即使是在并发量较大的情况下,这种场景也只是少量出现。

如果分支事务每次接收到一次携带事务上下文的业务请求,就检查一次该事务是否是活动状态,则会发现,这种请求绝大部分情况返回的结果都是请求事务当前是活动状态。然而,由于分支节点是首次收到请求,要检查就必须去上一级节点或者中心调度器(中心化设计)检索xid,而这种检查是有开销的。为了少量异常事务而添加该检查,会给大部分正常的事务带来不必要的开销,这是不划算的。

因此,byteTCC采用的策略是,既然这种情况是异常场景,那就让它按异常的方式先走下去,后续再考虑将其回撤掉。由于发生概率并不高,因此也不会给业务系统造成太大负担。

( byteTCC并未在B服务收到请求时判断是否有效。原因是此时判断会给绝大部分正常的请求增加处理逻辑而造成性能低下)这里的描述有点不太明白,空回滚这里处理会检索当前生效的事务了,所以正常的请求也会有检索操作吧,这里判断会增加的处理逻辑性能消耗在哪里呢?

menghuan123 commented 2 years ago

问题描述:A服务向B服务发起业务请求,该请求因网络阻塞等原因超时,此时A服务TM随即发起回滚。在A服务TM将全局事务回滚完毕后,B服务又收到了A先前发出的请求并执行。

上述这个场景存在多少概率呢?实际上,以我的既往经验(本人曾在一款商业应用服务器中间件中实现基于XA/2PC的分布式事务管理器)来看,即使是在并发量较大的情况下,这种场景也只是少量出现。

如果分支事务每次接收到一次携带事务上下文的业务请求,就检查一次该事务是否是活动状态,则会发现,这种请求绝大部分情况返回的结果都是请求事务当前是活动状态。然而,由于分支节点是首次收到请求,要检查就必须去上一级节点或者中心调度器(中心化设计)检索xid,而这种检查是有开销的。为了少量异常事务而添加该检查,会给大部分正常的事务带来不必要的开销,这是不划算的。

因此,byteTCC采用的策略是,既然这种情况是异常场景,那就让它按异常的方式先走下去,后续再考虑将其回撤掉。由于发生概率并不高,因此也不会给业务系统造成太大负担。

( byteTCC并未在B服务收到请求时判断是否有效。原因是此时判断会给绝大部分正常的请求增加处理逻辑而造成性能低下)这里的描述有点不太明白,空回滚这里处理会检索当前生效的事务了,所以正常的请求也会有检索操作吧,这里判断会增加的处理逻辑性能消耗在哪里呢?

请问下具体实现在源码里是哪些类呢?