bigywater.tech
微服务 · 54

Nacos:临时实例与持久实例

Nacos 的临时实例和持久实例有什么区别?服务端怎么判断实例没了?实例不健康会被删除吗?保护阈值到底保护什么?服务端重启之后各自怎样?这篇用 Nacos 3.2.4 和真的被杀、被冻住的客户端逐项量出来。

0.58 s vs 26.12 s
临时实例的客户端被 SIGKILL 和被 SIGSTOP 冻住后,实例从列表里消失的用时
61 s
持久实例停掉监听后过了约这么久,仍在列表里,healthy=false,没有被删除
4 → 0
保护阈值 0.2(不低于健康比例 1/5)时,客户端视图看到的 unhealthy 数,实际上有 4 个已经停了

临时实例靠连接

实测 · 本机执行输出
  让它消失的方式 | 子进程登记完成后到列表里可见 | 动作到列表里消失 | 期间 healthy 标志的变化(相对动作时刻)
  --------+----------------+----------+-------------------------
  优雅注销    | 0.20 s         | 0.68 s   | 0.0s:healthy=True       
  SIGKILL | 0.00 s         | 0.58 s   | 0.0s:healthy=True       
  SIGSTOP | 0.00 s         | 26.12 s  | 0.0s:healthy=True       

连接断了立刻消失;连接没断但对方没响应,要等服务端探测超时,期间一直报 healthy。

持久实例靠探活

实测 · 本机执行输出
  登记持久实例 p1(端口 9151):HTTP 200 {"code":0,"message":"success","data":"ok"}
  登记后立刻查:ephemeral=False,healthy=True
  监听一直开着,12 s 后:healthy=True
  关掉监听后:healthy 变 false 用了 0.6 s;此时管理 API healthyOnly=false 返回 1 个、healthyOnly=true 返回 0 个;客户端 API(healthyOnly=true)返回 1 个,其中 healthy=[False]
  再等 60 s(共离开约 61 s):实例仍在列表里,healthy=False
  重新监听同一个端口后:healthy 恢复用了 13.1 s
  从头没人监听的实例 p2:登记后立刻查 healthy=True;变 false 用了 3.4 s(从登记后第一次查询算起)

服务端主动探测,变 unhealthy 很快、恢复慢;没人续约不会被删除。

保护阈值

实测 · 本机执行输出
  4 个实例停掉监听后,3.4 s 在管理视图里全部变成 unhealthy;服务的 protectThreshold 初始值:0.0
  protectThreshold  | 管理视图 unhealthy / 总数 | 客户端视图 unhealthy / 总数 | 客户端 API healthyOnly=true 返回 | 管理 API healthyOnly=true 返回
  ------------------+---------------------+----------------------+-----------------------------+---------------------------
  0.0               | 4 / 5               | 4 / 5                | 5                           | 1                         
  0.1(PUT HTTP 200) | 4 / 5               | 4 / 5                | 5                           | 1                         
  0.2(PUT HTTP 200) | 4 / 5               | 0 / 5                | 5                           | 1                         
  0.5(PUT HTTP 200) | 4 / 5               | 0 / 5                | 5                           | 1                         
  0.0(PUT HTTP 200) | 4 / 5               | 4 / 5                | 5                           | 1                         
  健康比例 = 1 / 5 = 0.2。客户端视图在阈值不低于这个比例时把所有实例都报成 healthy(包括实际上已经停了的 4 个),低于时才如实返回;/nacos/v3/client/ns/instance/list 这一版对 healthyOnly 参数没有做过滤(本次实测,返回数与 false 时相同),管理 API 的 healthyOnly=true 则只返回原始状态为 healthy 的

阈值不低于健康比例时,客户端看到所有实例都是 healthy,包括已经停了的。

混用与重启

实测 · 本机执行输出
  (a1)服务里已经有临时实例,再登记持久实例:HTTP 400 '{"code":30000,"message":"server error","data":"errCode: 400, errMsg: Current service DEFAULT_GROUP@@mix is ephemeral service, can\'t register persistent instance. "}'
  (a2)服务里已经有持久实例,再用 SDK 登记临时实例:NacosException: Error [500]: errCode: 400, errMsg: Current service DEFAULT_GROUP@@mix2 is persistent service, can't register ephemeral instance. 
       两个服务的最终内容:mix → [('10.2.0.1', True)];mix2 → [('127.0.0.1', False)]
  Nacos 被 SIGKILL 后重启(从启动命令算起):HTTP 接口可用 6.7 s;之后持久实例 keep 在列表里出现用了 0.0 s(刚出现时 healthy=True,healthy 为 true 用了 0.0 s);临时实例 eph(SDK 客户端子进程一直活着)重新出现用了 14.3 s(以上都从接口可用的时刻开始算)
ERRORS {}

一个服务只能是一类;重启后持久实例数据还在,临时实例要靠客户端重连重新登记。

分步演示

Nacos 临时与持久实例
本步的对象

    本文用到的工具与边界

    • 本机 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 的子进程(用于真的 SIGKILL 和 SIGSTOP),持久实例用 /nacos/v3/admin/ns/instance 登记,“实例”是本进程里开的 TCP 监听;服务端的默认健康检查是 TCP;每种情形只测了 1 到 2 次(恢复用 13 s 在前后两次开发运行里一致,变 false 的 0.6 s / 1.5 s 因探测周期而不同)
    • 没有验证:Nacos 集群模式(Raft/Distro 同步)下的行为;HTTP / MySQL 类健康检查;持久实例在集群里谁来探活;临时实例的 gRPC 保活间隔是多少、SIGSTOP 的 26 s 由哪些参数构成(没有看源码或配置);保护阈值的本意和边界判断(只测了 0 到 0.5 里的几个值,阈值 0.2 和比例 0.2 相等时也触发了保护);SDK 的 list_instances(healthy_only=True)(探测时它在阈值调回 0 之后仍返回 5 个全是 healthy 的实例,和 HTTP 视图对不上,原因我没有查,所以文章里没有用它);Nacos 1.x 的 HTTP 心跳模式;权重、元数据与分组(见第 50 篇)
    京ICP备2026067502号-1京公网安备11010502063487号