网关404问题困扰我一年,为何迟迟未解决?

摘要:大家好,我是小富~ 最近同事找我帮忙排查一个"诡异"的 Bug,说困扰了他们一年多一直没解决。我接手后花了一些时间定位到了问题根源,今天就来跟大家分享一下这个问题的排查过程和解决方案。 问
大家好,我是小富~ 最近同事找我帮忙排查一个"诡异"的 Bug,说困扰了他们一年多一直没解决。我接手后花了一些时间定位到了问题根源,今天就来跟大家分享一下这个问题的排查过程和解决方案。 问题描述 同事使用的是 SpringCloud Gateway 3.0.1 + JDK8,整合了 Nacos 做动态路由配置。问题是:每次修改 Nacos 的路由配置后,网关的 API 请求就会出现 404 错误,但重启网关后又能恢复正常。 听到这个问题,我的第一反应是:Nacos 配置更新后,网关的缓存数据可能没有及时更新。带着这个猜想,我开始深入排查。 环境准备 首先准备了 3 个后端服务实例,端口分别为 8103、12040、12041,在 Nacos 中配置了对应的网关路由:xiaofu-8103、xiaofu-12040、xiaofu-12041,并将它们放在同一个权重组 xiaofu-group 中,实现基于权重的负载均衡。 - id: xiaofu-8103 uri: http://127.0.0.1:8103/ predicates: - Weight=xiaofu-group, 2 - Path=/test/version1/** filters: - RewritePath=/test/version1/(?<segment>.*),/$\{segment} - id: xiaofu-12040 uri: http://127.0.0.1:12040/ predicates: - Weight=xiaofu-group, 1 - Path=/test/version1/** filters: - RewritePath=/test/version1/(?<segment>.*),/$\{segment} - id: xiaofu-12041 uri: http://127.0.0.1:12041/ predicates: - Weight=xiaofu-group, 2 - Path=/test/version1/** filters: - RewritePath=/test/version1/(?<segment>.*),/$\{segment} 使用 JMeter 进行持续请求测试,为了便于日志追踪,给每个请求参数都添加了随机数。 准备完成后启动 JMeter 循环请求,观察到三个实例都有日志输出,说明网关的负载均衡功能正常。 问题排查 为了获取更详细的日志信息,我将网关的日志级别调整为 TRACE。 启动 JMeter 后,随机修改三个实例的路由属性(uri、port、predicates、filters),请求没有出现报错,网关控制台也显示了更新后的路由属性,说明 Nacos 配置变更已成功同步到网关。 接下来尝试去掉一个实例 xiaofu-12041,这时发现 JMeter 请求开始出现 404 错误,成功复现问题! 查看网关控制台日志时,惊奇地发现已删除的实例 xiaofu-12041 的路由配置仍然存在,甚至还被选中(chosen)处理请求。问题根源找到了:虽然 Nacos 中删除了实例路由配置,但网关在实际负载均衡时仍然使用旧的路由数据。 继续深入排查,发现在路由的权重信息(Weights attr)中也存在旧的路由数据。至此基本确定问题:在计算实例权重和负载均衡时,网关使用了陈旧的缓存数据。 源码分析 通过分析源码,发现了一个专门计算权重的过滤器 WeightCalculatorWebFilter。它内部维护了一个 groupWeights 变量来存储路由权重信息。当配置变更事件发生时,会执行 addWeightConfig(WeightConfig weightConfig) 方法来更新权重配置。
阅读全文