如何解决Sentinel和Seata AT分布式事务的冲突?
一、冲突根源Seata ATGlobalTransactional依赖异常向上抛出感知分支调用失败触发全局事务回滚Sentinel Feign 自动熔断远程调用超时、异常、触发熔断阈值时直接执行本地Fallback降级逻辑吞掉原始异常最终现象下游RM分支未执行业务SQL、未注册分支事务但TM无异常感知全局事务正常提交多库数据不一致。⚠️ 关键区分限流规则FlowRule抛出BlockException异常会向上抛出不会干扰Seata事务可以正常共存熔断降级规则DegradeRule Feign Fallback吞异常是唯一冲突点。二、五大落地解决方案方案1分层开关隔离生产标准首选零侵入核心思路全局开启Sentinel限流能力仅对GlobalTransactional包裹的事务链路单独关闭Feign Sentinel自动熔断非事务查询接口保留熔断降级。1全局配置开启限流默认关闭Feign熔断# 全局启用Sentinelspring.cloud.sentinel.dashboard:127.0.0.1:8080# 默认全局关闭Feign sentinel降级feign.sentinel.enabled:false此时所有Feign调用不会触发Fallback降级但接口QPS、热点限流规则依然正常生效。2非事务查询接口单独开启降级局部开启不修改全局配置单独给查询类Feign客户端指定Sentinel降级工厂FeignClient(valuegoods-service,fallbackFactoryGoodsFeignFallbackFactory.class,configurationFeignSentinelConfig.class)publicinterfaceGoodsFeignClient{// 纯查询接口无分布式事务允许降级}配套配置类单独开启该Feign客户端的Sentinel熔断互不影响事务链路。优势写事务链路绝对安全Seata回滚不受任何干扰查询接口正常享受熔断降级高可用保护无需改动业务代码纯配置隔离运维清晰。方案2事务内Feign降级后主动抛异常无法全局关闭降级时在Fallback降级方法里主动抛出业务运行时异常让TM捕获异常触发全局回滚。局限下游RM根本没执行SQL无分支事务Seata只能回滚上游已执行本地事务下游无任何操作不会造成脏数据但无法重试恢复下游服务。1Feign降级工厂代码ComponentpublicclassStockFeignFallbackFactoryimplementsFallbackFactoryStockFeignClient{OverridepublicStockFeignClientcreate(Throwablecause){returnnewStockFeignClient(){Overridepublicvoiddeduct(LonggoodsId,Integernum){log.error(库存服务远程调用熔断降级,cause);// 主动抛出运行时异常向上传递给TMthrownewRuntimeException(下游库存服务不可用事务回滚);}};}}2TM全局事务注解GlobalTransactional(rollbackForException.class)publicvoidcreateOrder(){insertOrder();stockFeignClient.deduct(1L,10);}降级抛出异常 → TM感知 → 全局事务回滚订单插入操作。适用场景老项目已经全局开启feign.sentinel.enabledtrue不方便整体回滚临时兼容改造。方案3返回值判断手动触发Seata回滚降级方法返回标记结果布尔/枚举TM收到降级标识后手动调用Seata API强制回滚全局事务。1Feign接口定义返回值publicinterfaceStockFeignClient{// true扣减成功false降级/调用失败Booleandeduct(LonggoodsId,Integernum);}2降级方法返回失败标识OverridepublicBooleandeduct(LonggoodsId,Integernum){log.warn(库存服务熔断降级);returnfalse;}3TM业务代码主动判断并回滚GlobalTransactionalpublicvoidcreateOrder(){insertOrder();BooleanresstockFeignClient.deduct(1L,10);if(!res){// 手动触发全局事务回滚StringxidRootContext.getXID();GlobalTransactionContext.reload(xid).rollback();thrownewRuntimeException(下游服务降级事务已回滚);}}方案4线程隔离策略改造禁止Sentinel线程池隔离Sentinel两种隔离模式线程池隔离Feign调用新开独立线程XID上下文丢失必然断事务信号量隔离复用调用方原有线程XID上下文保留不会丢失事务标识。事务内Feign调用的Sentinel规则强制设置隔离模式为信号量隔离避免线程切换丢失XID。⚠️ 该方案仅保证上下文不丢失依然存在降级吞异常问题必须搭配方案2一起使用不单独推荐。方案5架构拆分根治写操作分布式事务链路不使用Feign同步调用改用RocketMQ本地消息表可靠消息最终一致性异步解耦事务提交成功后发送MQ库存、余额服务消费消息异步执行扣减彻底规避同步Feign熔断冲突。读操作查询、非核心附属信息保留Feign Sentinel熔断降级本地缓存兜底提升可用性。三、配套边界约束细则1限流规则完全兼容无需改动Sentinel流控、热点参数限流触发时抛出BlockException异常会向上抛出Seata正常捕获回滚可以放心共存仅熔断降级需要隔离。2全局异常处理器注意事项RestControllerAdvice不能吞掉BlockException、业务运行时异常否则Seata依然感知不到异常事务无法回滚。3Nacos持久化规则拆分Sentinel规则持久化到Nacos时分开维护两套规则事务写接口仅配置流控规则不配置降级规则查询读接口流控降级规则完整配置。四、最终落地选型建议新项目首选方案1分层开关隔离架构干净、无业务代码侵入、事务安全性最高阿里微服务生产标准实践存量老项目改造选方案2改动量小只修改Fallback降级类快速修复事务不一致问题高并发秒杀长事务场景直接采用方案5消息异步化拆分从架构层面彻底消除同步调用冲突。五、高频踩坑误区降级方法抛异常就能让下游RM回滚降级时远程Feign根本没有发起HTTP请求下游RM没有执行SQL、没有注册分支事务只能回滚上游TM本地事务下游无操作不会产生脏数据但无法重试恢复下游服务。误区Sentinel所有规则都会和Seata冲突只有DegradeRule熔断降级会吞异常冲突FlowRule限流无任何冲突可正常使用。误区信号量隔离就能彻底解决冲突仅保留XID上下文无法解决降级吞异常问题必须额外抛出异常触发回滚。