做的差的网站抖音合作推广平台

张小明 2026/1/11 13:07:36
做的差的网站,抖音合作推广平台,河南省城乡与住房建设厅网站首页,在线做汉字头像的网站最近同事找我帮忙排查一个诡异的 Bug#xff0c;说困扰了他们一年多一直没解决。我接手后花了一些时间定位到了问题根源#xff0c;今天就来跟大家分享一下这个问题的排查过程和解决方案。 问题描述 同事使用的是 SpringCloud Gateway 3.0.1 JDK8#xff0c;…最近同事找我帮忙排查一个诡异的 Bug说困扰了他们一年多一直没解决。我接手后花了一些时间定位到了问题根源今天就来跟大家分享一下这个问题的排查过程和解决方案。问题描述同事使用的是SpringCloud Gateway 3.0.1JDK8整合了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: - Weightxiaofu-group, 2 - Path/test/version1/** filters: - RewritePath/test/version1/(?segment.*),/$\{segment} - id: xiaofu-12040 uri: http://127.0.0.1:12040/ predicates: - Weightxiaofu-group, 1 - Path/test/version1/** filters: - RewritePath/test/version1/(?segment.*),/$\{segment} - id: xiaofu-12041 uri: http://127.0.0.1:12041/ predicates: - Weightxiaofu-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)方法来添加权重配置。Override public void onApplicationEvent(ApplicationEvent event) { if (event instanceof PredicateArgsEvent) { handle((PredicateArgsEvent) event); } else if (event instanceof WeightDefinedEvent) { addWeightConfig(((WeightDefinedEvent) event).getWeightConfig()); } else if (event instanceof RefreshRoutesEvent routeLocator ! null) { if (routeLocatorInitialized.compareAndSet(false, true)) { routeLocator.ifAvailable(locator - locator.getRoutes().blockLast()); } else { routeLocator.ifAvailable(locator - locator.getRoutes().subscribe()); } } }addWeightConfig方法的注释明确说明该方法仅创建新的GroupWeightConfig而不进行修改。这意味着它只能新建或覆盖路由权重无法清理已删除的路由权重信息。void addWeightConfig(WeightConfig weightConfig) { String group weightConfig.getGroup(); GroupWeightConfig config; // only create new GroupWeightConfig rather than modify // and put at end of calculations. This avoids concurency problems // later during filter execution. if (groupWeights.containsKey(group)) { config new GroupWeightConfig(groupWeights.get(group)); } else { config new GroupWeightConfig(group); } final AtomicInteger index new AtomicInteger(0); ....省略..... if (log.isTraceEnabled()) { log.trace(Recalculated group weight config config); } // only update after all calculations groupWeights.put(group, config); }解决方案找到问题根源后解决方案就清晰了开始我怀疑可能是springcloud gateway 版本问题将版本升级到了4.1.0但结果还是存在这个问题。看来只能手动更新缓存解决了需要监听Nacos路由配置变更事件获取最新路由配置并更新groupWeights中的权重数据。以下是实现的解决方案代码Slf4j Configuration public class WeightCacheRefresher { Autowired private WeightCalculatorWebFilter weightCalculatorWebFilter; Autowired private RouteDefinitionLocator routeDefinitionLocator; Autowired private ApplicationEventPublisher publisher; /** * 监听路由刷新事件同步更新权重缓存 */ EventListener(RefreshRoutesEvent.class) public void onRefreshRoutes() { log.info(检测到路由刷新事件准备同步更新权重缓存); syncWeightCache(); } /** * 同步权重缓存与当前路由配置 */ public void syncWeightCache() { try { // 获取 groupWeights 字段 Field groupWeightsField WeightCalculatorWebFilter.class.getDeclaredField(groupWeights); groupWeightsField.setAccessible(true); // 获取当前的 groupWeights 值 SuppressWarnings(unchecked) MapString, Object groupWeights (MapString, Object) groupWeightsField.get(weightCalculatorWebFilter); if (groupWeights null) { log.warn(未找到 groupWeights 缓存); return; } log.info(当前 groupWeights 缓存: {}, groupWeights.keySet()); // 获取当前所有路由的权重组和路由ID final SetString currentRouteIds new HashSet(); final MapString, MapString, Integer currentGroupRouteWeights new HashMap(); routeDefinitionLocator.getRouteDefinitions() .collectList() .subscribe(definitions - { definitions.forEach(def - { currentRouteIds.add(def.getId()); def.getPredicates().stream() .filter(predicate - predicate.getName().equals(Weight)) .forEach(predicate - { MapString, String args predicate.getArgs(); String group args.getOrDefault(_genkey_0, unknown); int weight Integer.parseInt(args.getOrDefault(_genkey_1, 0)); // 记录每个组中当前存在的路由及其权重 currentGroupRouteWeights.computeIfAbsent(group, k - new HashMap()) .put(def.getId(), weight); }); }); log.info(当前路由配置中的路由ID: {}, currentRouteIds); log.info(当前路由配置中的权重组: {}, currentGroupRouteWeights); // 检查每个权重组移除不存在的路由更新权重变化的路由 SetString groupsToRemove new HashSet(); SetString groupsToUpdate new HashSet(); for (String group : groupWeights.keySet()) { if (!currentGroupRouteWeights.containsKey(group)) { // 整个权重组不再存在 groupsToRemove.add(group); log.info(权重组 [{}] 不再存在于路由配置中将被移除, group); continue; } // 获取该组中当前配置的路由ID和权重 MapString, Integer configuredRouteWeights currentGroupRouteWeights.get(group); // 获取该组中缓存的权重配置 Object groupWeightConfig groupWeights.get(group); try { // 获取 weights 字段 Field weightsField groupWeightConfig.getClass().getDeclaredField(weights); weightsField.setAccessible(true); SuppressWarnings(unchecked) LinkedHashMapString, Integer weights (LinkedHashMapString, Integer) weightsField.get(groupWeightConfig); // 找出需要移除的路由ID SetString routesToRemove weights.keySet().stream() .filter(routeId - !configuredRouteWeights.containsKey(routeId)) .collect(Collectors.toSet()); // 找出权重发生变化的路由ID SetString routesWithWeightChange new HashSet(); for (Map.EntryString, Integer entry : weights.entrySet()) { String routeId entry.getKey(); Integer cachedWeight entry.getValue(); if (configuredRouteWeights.containsKey(routeId)) { Integer configuredWeight configuredRouteWeights.get(routeId); if (!cachedWeight.equals(configuredWeight)) { routesWithWeightChange.add(routeId); log.info(路由 [{}] 的权重从 {} 变为 {}, routeId, cachedWeight, configuredWeight); } } } // 找出新增的路由ID SetString newRoutes configuredRouteWeights.keySet().stream() .filter(routeId - !weights.containsKey(routeId)) .collect(Collectors.toSet()); if (!routesToRemove.isEmpty() || !routesWithWeightChange.isEmpty() || !newRoutes.isEmpty()) { log.info(权重组 [{}] 中有变化删除 {}权重变化 {}新增 {}, group, routesToRemove, routesWithWeightChange, newRoutes); // 如果有任何变化我们将重新计算整个组的权重 groupsToUpdate.add(group); } // 首先移除需要删除的路由 for (String routeId : routesToRemove) { weights.remove(routeId); } // 如果权重组中没有剩余路由则移除整个组 if (weights.isEmpty()) { groupsToRemove.add(group); log.info(权重组 [{}] 中没有剩余路由将移除整个组, group); } } catch (Exception e) { log.error(处理权重组 [{}] 时出错, group, e); } } // 移除不再需要的权重组 for (String group : groupsToRemove) { groupWeights.remove(group); log.info(已移除权重组: {}, group); } // 更新需要重新计算的权重组 for (String group : groupsToUpdate) { try { // 获取该组中当前配置的路由ID和权重 MapString, Integer configuredRouteWeights currentGroupRouteWeights.get(group); // 移除旧的权重组配置 groupWeights.remove(group); log.info(已移除权重组 [{}] 以便重新计算, group); // 为每个路由创建 WeightConfig 并调用 addWeightConfig 方法 Method addWeightConfigMethod WeightCalculatorWebFilter.class.getDeclaredMethod(addWeightConfig, WeightConfig.class); addWeightConfigMethod.setAccessible(true); for (Map.EntryString, Integer entry : configuredRouteWeights.entrySet()) { String routeId entry.getKey(); Integer weight entry.getValue(); WeightConfig weightConfig new WeightConfig(routeId); weightConfig.setGroup(group); weightConfig.setWeight(weight); addWeightConfigMethod.invoke(weightCalculatorWebFilter, weightConfig); log.info(为路由 [{}] 添加权重配置组 [{}]权重 {}, routeId, group, weight); } } catch (Exception e) { log.error(重新计算权重组 [{}] 时出错, group, e); } } log.info(权重缓存同步完成当前缓存的权重组: {}, groupWeights.keySet()); }); } catch (Exception e) { log.error(同步权重缓存失败, e); } } }如此一来每次更新nacos路由配置就会监听到配置变更事件进而用最新的实例数据来更新本地的路由权重数据。网上找一圈并没发现官方的修改意见可能是咱们使用方式不对导致的要不如此明显的BUG早就有人改了吧程序员小富xiaofucode.com 以搞钱为源动力的程序员学习指南90篇原创内容公众号面试 · 目录上一篇令牌桶VS漏桶谁才是流量控制的“最优解”下一篇上线别再“一刀切”Gateway 做流量染色 灰度发布告别线上事故阅读 775​
版权声明:本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!

遵义网站建公司wordpress 图片优化

新手做 Agent,80% 时间搭建,20% 时间分析问题,老手正好反过来。 我最近看了吴恩达的 Agentic AI 课程,这是他的观察。 新手往往会踩一种坑: 花两周搭完系统,联调时发现第一步就错了,后面所有…

张小明 2026/1/9 17:39:49 网站建设

网站建设合同模式万网解压缩wordpress

探索 Spock 测试框架:高效测试的利器 1. 什么是 Spock 测试框架 Spock 是一个强大的测试框架,可自动化执行测试流程并生成测试报告。它的应用场景广泛,能用于后端代码、网页以及 HTTP 服务等的测试。 Spock 具有以下显著特点: - 全面性(COMPREHENSIVE) :Spock 是一…

张小明 2026/1/9 19:20:31 网站建设

网站建设策划 流程长沙做网站seo优化外包

sceasy:单细胞数据格式转换的终极解决方案 【免费下载链接】sceasy A package to help convert different single-cell data formats to each other 项目地址: https://gitcode.com/gh_mirrors/sc/sceasy 在单细胞数据分析的复杂世界中,数据格式的…

张小明 2026/1/9 19:20:29 网站建设

计算机基础网站建设和网络安全啊里网站制作

终极指南:如何使用SuperDesign在IDE中快速生成UI设计 【免费下载链接】superdesign 项目地址: https://gitcode.com/gh_mirrors/su/superdesign 在当今快速发展的软件开发领域,设计效率直接影响项目进度。SuperDesign作为首个开源设计Agent&…

张小明 2026/1/9 19:20:27 网站建设

建广告网站需要多少钱响应式网站开发软件

UniBest跨端开发框架终极实战指南:从零构建多平台应用 【免费下载链接】unibest unibest - 最好用的 uniapp 开发框架。unibest 是由 uniapp Vue3 Ts Vite4 UnoCss UniUI 驱动的跨端快速启动模板,使用 VS Code 开发,具有代码提示、自动格…

张小明 2026/1/9 19:20:25 网站建设

基于flash网站设计做网站服务器配置怎么选

Kotaemon框架的内存优化实践:构建高效RAG系统的工程之道 在大语言模型(LLM)日益渗透企业服务与智能交互场景的今天,我们不再仅仅追求“能回答问题”的AI系统,而是要打造可信赖、低延迟、可持续运行的生产级智能体。尤…

张小明 2026/1/9 19:20:23 网站建设