配置推送延迟从 30 秒打到 10 毫秒Nacos 1.x 和 2.x 源码级对比改了配置30 秒后才生效压测发现支付服务的超时时间设太短需要在 Nacos 控制台把payment.timeout从 3000 改到 5000。改完。保存。发布成功。然后盯着 Grafana 看了 30 秒。超时率纹丝不动。第 31 秒。超时率从 12% 跌到 0.3%。所有实例一次性拉到了新配置。这就是 Nacos 1.x 长轮询的机制——不是推送是客户端在控制台发布 30 秒后终于等到了下一次轮询。最快 1 秒最慢 30 秒平均 15 秒。取决于你改配置的时刻落在哪个轮询周期里。2.x 把这件事从 30 秒打到了 10 毫秒。不是优化是底层通信模型换了。这篇文章把两个版本的配置推送链路拆开对比——长轮询怎么 Hold 的、gRPC 怎么 Push 的、代码层面到底差了哪一步。全景两条链路同一终点2.x gRPC 双向流控制台发布配置ConfigControllerpublishConfig()ConfigChangeNotifier变更通知GrpcPushService遍历订阅者 gRPC 连接客户端收到 Push立即拉取新配置1.x 长轮询控制台发布配置ConfigControllerpublishConfig()DumpService内存变更事件LongPollingServiceHold 住 HTTP 请求客户端轮询到期拉取新配置1.x 和 2.x 的前两步一样——控制台发布、DumpService 生成变更事件。分叉在第三步1.x Hold 住 HTTP 请求等客户端来拿2.x 通过 gRPC 主动推。1.x 长轮询一个等待游戏服务端LongPollingService配置发布后DumpService 生成一个LocalDataChangeEvent。LongPollingService 收到事件检查当前有没有客户端正在长轮询这个 Data ID。有就立即返回——这是最快的情况。没有就等着客户端下一次轮询时才能拿到。// 服务端 1.x 源码大幅简化publicclassLongPollingService{// 客户端发来的长轮询请求被 Hold 在这里privateMapString,ListClientLongPollingallSubsnewConcurrentHashMap();publicvoidaddLongPollingClient(StringdataId,ClientLongPollingclient){allSubs.computeIfAbsent(dataId,k-newArrayList()).add(client);}// 配置变更时被 DumpService 调用publicvoidonConfigChange(StringdataId){ListClientLongPollingclientsallSubs.remove(dataId);if(clients!null){for(ClientLongPollingclient:clients){client.sendResponse(配置已变更);// 立即返回}}}}// 客户端 1.x 源码大幅简化publicclassClientWorker{privateScheduledExecutorServiceexecutor;publicvoidstartLongPolling(){executor.scheduleWithFixedDelay(()-{// 发 HTTP GET 到 /nacos/v1/cs/configs/listener// 请求头带上 Long-Pulling-Timeout: 30000HttpResponseresponsehttpGet(/nacos/v1/cs/configs/listener,Long-Pulling-Timeout: 30000);if(response.isChanged()){// 有变更立即拉新配置StringnewConfiggetConfig(dataId,group);listener.receiveConfigInfo(newConfig);}// 没变更就等下次轮询},0,1,TimeUnit.SECONDS);}}客户端每 1 秒发一次轮询请求服务端 Hold 住最长 30 秒。如果 30 秒内没有变更返回空客户端等 1 秒再发。所以最坏情况你刚好在一个 Hold 刚开始时改配置要等 30 秒 Hold 结束 1 秒间隔 31 秒。1.x 的延迟分布最快 1 秒刚好赶上轮询窗口、最慢 31 秒刚好错过、平均 15 秒。2.x gRPC 双向流不说废话有事直说2.x 不再 Hold HTTP 请求。每个 Nacos 客户端启动时建一条 gRPC 双向流连接回顾第四篇 2.4 讲过。配置变更通知就走这条连接。服务端// 服务端 2.x 源码大幅简化publicclassGrpcPushService{// 所有客户端的 gRPC 连接privateMapString,StreamObserverclientConnectionsnewConcurrentHashMap();// 配置变更时被 ConfigChangeNotifier 调用publicvoidpushConfigChange(StringdataId,Stringgroup,Stringtenant){// 找到所有订阅了这个配置的客户端连接StringconfigKeytenantgroupdataId;ListStringclientIdssubscriberMap.get(configKey);if(clientIds!null){for(StringclientId:clientIds){StreamObserverobserverclientConnections.get(clientId);if(observer!null){// 直接 Push不等客户端来问observer.onNext(ConfigChangeNotifyRequest.newBuilder().setDataId(dataId).setGroup(group).setTenant(tenant).build());}}}}}没有 Hold。没有等待。配置变了一毫秒内就往所有订阅者的 gRPC 连接上发。客户端// 客户端 2.x 源码大幅简化publicclassGrpcConfigClient{privateStreamObserverConfigChangeNotifyRequestrequestStream;publicvoidonConfigChangeNotify(ConfigChangeNotifyRequestnotify){// 服务端 Push 过来的通知// 立即触发拉取新配置StringnewConfigconfigService.getConfig(notify.getDataId(),notify.getGroup(),notify.getTenant());listener.receiveConfigInfo(newConfig);}}客户端不再跑定时器。它只是等着。gRPC 连接上有消息过来就处理。没有就安静待着。7 个类的接力业务代码GrpcClientGrpcPushServiceConfigChangeNotifierDumpServiceConfigController控制台业务代码GrpcClientGrpcPushServiceConfigChangeNotifierDumpServiceConfigController控制台publishConfig(dataId, content)dump 到内存 MySQLfireConfigChangeEvent(dataId)pushConfigChange(dataId, group, tenant)observer.onNext(notify)onConfigChangeNotify(notify)receiveConfigInfo(newConfig)配置推送 7 个类的接力ConfigController → DumpService → ConfigChangeNotifier → GrpcPushService → GrpcClient → 业务回调。全程无阻塞、无等待、无轮询。实际延迟取决于网络延迟 protobuf 序列化耗时。局域网环境下 5~10 毫秒跨机房 15~30 毫秒。比 1.x 的 15 秒平均值快了三个数量级。一张图带走1.x vs 2.x 断点位置1.x2.x有没有正常断开控制台发布配置Nacos 版本?ConfigController.publishConfig()ConfigController.publishConfig()DumpService写内存 MySQL有客户端正在长轮询?立即返回延迟: 1~5秒等待轮询周期延迟: 最多31秒DumpService写内存 MySQLConfigChangeNotifier触发变更事件gRPC 连接是否正常?GrpcPushService 推送延迟: 5~30ms客户端下次重连后全量拉取配置排查断点:LongPollingService是否收到事件排查断点:gRPC 连接状态clientConnections Map截图保存。排查配置改了不生效就从这张图走先看 Nacos 版本1.x 追 LongPollingService 的 allSubs Map2.x 追 GrpcPushService 的 clientConnections Map。你们现在用的 Nacos 哪个版本评论区留个数字1还在 1.x 硬扛 2已升 2.x 享受 10ms 推送 3没用 Nacos 做配置中心。顺便说一句你见过最离谱的配置延迟是多少。