bigywater.tech
微服务 · 55

变更通知:Nacos 的推拉结合与配置中心的长轮询

配置中心怎么把变更送到客户端?推送、长轮询、短轮询的延迟和请求量差多少?刚注册监听就改配置会不会漏?客户端暂时断开再回来,中间的变更怎么办?这篇用 Nacos 3.2.4 的 SDK 和一个自写的长轮询服务逐项量出来。

71.3 ms
Nacos SDK 推送的中位延迟(1 个监听者,30 次发布);30 个监听者是 121.9 ms
约 6 s
add_listener 返回后到服务端开始对它推送的时间,这段时间里发布的变更没有回调
0.8 ms vs 603.2 ms
自写长轮询与 1 s 短轮询的中位延迟(长轮询 50 s 里发了 13 个请求,短轮询 52 个)

推送延迟

实测 · 本机执行输出
  监听者数 | 发布次数 | 收到回调数/应收 | 延迟 最小 / 中位 / 最大(ms)  | 同一次发布各监听者收到时间的跨度,中位(ms)
  -----+------+----------+----------------------+------------------------
  1    | 30   | 30/30    | 14.7 / 71.3 / 127.4  | 0.0                    
  30   | 10   | 300/300  | 54.3 / 121.9 / 156.9 | 1.9                    
  add_listener 返回(子进程打印 ready)之后,到每个监听者都收到过第一次推送的时间:1 个监听者 6.2 s;30 个监听者 6.1 s(这段时间里的发布没有回调,所以上表只统计生效之后的发布)
  发布调用(POST)自己也要花时间;这里的延迟从调用发出之前算起,所以包含服务端处理发布的时间

Nacos 的 SDK 靠 gRPC 长连接接收推送;延迟是几十毫秒,监听者多了略有增加;监听刚注册的约 6 s 内发布的变更没有回调。

推送、长轮询、短轮询

实测 · 本机执行输出
  方式               | 收到变更数 | 延迟 最小 / 中位 / 最大(ms)      | 50 s 里发出的 HTTP 请求数
  -----------------+-------+--------------------------+-------------------
  Nacos 推送(SDK 监听) | 10/10 | 39.1 / 63.0 / 130.6      | (gRPC 长连接,没有统计)   
  短轮询 1 s          | 9/10  | 164.7 / 603.2 / 1010.6   | 52                
  短轮询 5 s          | 6/10  | 1272.3 / 2131.0 / 4445.9 | 11                
  长轮询(最多挂起 10 s)   | 10/10 | 0.4 / 0.8 / 1.6          | 13                
  short1(间隔 1 s)没有看到的变更:m3(与下一次变更相隔 0.15 s)
  short5(间隔 5 s)没有看到的变更:m1(与下一次变更相隔 0.56 s), m3(与下一次变更相隔 0.15 s), m4(与下一次变更相隔 2.07 s), m5(与下一次变更相隔 1.18 s)
  轮询看到的是“轮询那一刻的最新值”,所以没看到的变更对应上面与下一次变更的间隔;短轮询的请求数只取决于间隔,与变更多少无关;长轮询在没有变化时每个超时周期发一次请求,有变化时立即返回

短轮询的延迟在 0 到间隔之间,请求量只取决于间隔;长轮询接近一次往返、请求量取决于超时;轮询到的只是当前最新值。

暂时联系不上

实测 · 本机执行输出
  情形          | 恢复后收到的回调数 | 最后一个回调的内容     | 最后一个回调距恢复 | 恢复后的全部回调(内容@距恢复秒数)
  ------------+-----------+---------------+-----------+-------------------
  (a)冻住 5 s   | 1         | f2            | 0.00 s    | f2@0.00           
  (b)冻住 45 s  | 1         | f2            | 0.22 s    | f2@0.22           
  (c)Nacos 重启 | 1         | after-restart | 0.07 s    | after-restart@0.07
ERRORS {}

客户端冻住或服务端重启后,客户端拿到的是最新内容,中间的几次变更不会各自回调。

分步演示

配置变更通知
本步的对象

    本文用到的工具与边界

    • 本机 macOS 27 arm64 / Python 3.14.8 / Go / nginx / Envoy / etcd / Consul / Nacos / OpenTelemetry / Prometheus(按各篇注明用到哪些及版本);所有服务都是本机自己起的进程,端口 9150 以上,只监听 127.0.0.1,不连任何外部服务,不碰本机已有的实例;故障用 kill -9 进程、让连接断开或在代码里注入延迟与错误来制造;计时用 time.perf_counter,数字每次运行会有小幅抖动。Nacos 是 3.2.4(单机,Java 17),客户端是 nacos-sdk-python 3.2.0(每个监听者是子进程里的一个 SDK 客户端);长轮询和短轮询对照的是我自己写的几十行 Python 配置服务,不是 Nacos 的实现;所有时间都是同一台机器上的 time.time();30 个监听者在同一个子进程里,所以与分布在多台机器上的 30 个客户端有差别;“6 s 的生效空窗”是这个 SDK 版本的实测(在第一次运行里被我发现,之后的数字都是等它生效后量的),原因我没有查
    • 没有验证:Java SDK、Spring Cloud 的配置刷新(见后面的篇目);HTTP 长轮询接口(/nacos/v1/cs/configs/listener 和 /nacos/v2/cs/config/listener 在这个版本里 404,所以没有测 Nacos 自带的长轮询);集群模式下推送给大量客户端(只测了 30 个监听者);gRPC 保活参数;Nacos 灰度发布(beta)与按 tag 的配置;配置很大时的推送;服务端判断死连接后清理监听的细节
    京ICP备2026067502号-1京公网安备11010502063487号