注册中心抖动,推送延迟到了 8 秒
去年我们把配置中心/注册中心从 Nacos 1.x 升到 2.0,起因是一次线上抖动:一个服务下线,但网关隔了 8 秒才感知到,期间一大波请求打到了已死的实例。翻 Nacos 1.x 的源码才知道,它用的是客户端 10 秒一次 HTTP 轮询去拉变更,服务端有了新配置/新实例,最多要等一个轮询周期才能推到客户端。这是个天生就有延迟的模型。
Nacos 2.0 的核心改造:gRPC 长连接
Nacos 2.0 把通信模型整个换了:用 gRPC 长连接替代 HTTP 轮询。客户端启动后和Ubuntu 服务器建立一条双向流(bidi stream),服务端一旦有配置变更或实例上下线,主动 push 给这条连接,不再等客户端来问。
这带来的变化是本质性的:
- 配置/服务发现的推送延迟从"最长一个轮询周期(10s)"降到毫秒级。
- 客户端不再周期性施压,服务端连接模型从"海量短轮询"变成"少量长连接",整体负载下降。
长连接到底快在哪
1.x 的轮询模式:1000 个客户端每 10 秒拉一次,服务端每秒要处理 100 个请求,且大部分是"没变化"的空拉。2.0 长连接:1000 个客户端各自占一条连接,平时零请求,只在变更时收 push。
我们在测试环境对比了一次"批量下线 200 个实例,网关感知耗时":
| 版本 | 推送模式 | 网关感知平均耗时 | 服务端空拉 QPS |
|---|---|---|---|
| Nacos 1.4 | HTTP 轮询(10s) | 7.8 秒 | 约 100/s |
| Nacos 2.1 | gRPC 长连接 push | 120 毫秒 | 0(变更才推) |
升级时的两个坑
升级不是简单换 jar,我踩了两个必须提醒的坑。
坑一:新增了两个端口
2.0 为了兼容老客户端(1.x 仍走 HTTP),保留了旧端口,同时新增了 gRPC 端口:在主端口(默认 8848)基础上,8848 + 1000 = 9848 是 gRPC 客户端通信口,8848 + 1001 = 9849 是 gRPC 集群间通信口。K8s 的 Service 和防火墙必须把这两个端口放开,否则新客户端连不上:
# 容器内实际监听
$ netstat -tlnp | grep -E '8848|9848|9849'
tcp 0.0.0.0:8848 # HTTP,老客户端
tcp 0.0.0.0:9848 # gRPC 客户端
tcp 0.0.0.0:9849 # gRPC 集群间
我们第一次升级后,新客户端一直连不上,查了半天才发现是安全组没放行 9848。
坑二:数据兼容与双写
Nacos 2.0 对底层存储结构有调整。官方提供了平滑升级路径:先升级服务端,服务端会做新老协议双写,让 1.x 和 2.x 客户端都能正常工作;观察一段时间确认没问题后,再逐步把客户端升级到 2.x SDK。我们遵循"服务端先升、客户端后升"的顺序,灰度了三天,没出现数据不一致。
哪些场景收益最大
- 服务发现对时效性敏感的业务(网关路由、熔断降级),推送延迟从秒级降到百毫秒,故障感知快了一个量级。
- 大集群(上千实例)下,长连接比轮询省资源。
- 配置变更要求"即时生效"的,体验提升明显。
就写到这。如果哪天你也被《Nacos 2.0 长连接改造与性能优化》里同一个坑绊住,回来翻这篇,能省半小时。