9.4.4 服务发现与订阅推送机制

在 Nacos 的服务注册与发现体系中,服务发现是客户端获取可用服务实例列表的核心流程,订阅推送机制决定了服务变化如何高效通知客户端。以下结合原理草图、命令示例、排错与练习说明。

服务发现流程#

文章图片
  1. 客户端发起查询:SDK 或 OpenAPI 请求指定服务的实例列表。
  2. 注册中心返回结果:返回健康状态、权重、元数据等。
  3. 客户端缓存与刷新:缓存结果并通过订阅或定时拉取刷新。

示例:OpenAPI 获取实例列表#

# 查询指定服务的实例列表(namespaceId 可选,默认 public)
curl -s "http://127.0.0.1:8848/nacos/v1/ns/instance/list?serviceName=order-service&groupName=DEFAULT_GROUP" \
| jq '.'

# 预期效果:返回 instances 数组、hosts、health、weight 等信息

示例:按集群过滤#

curl -s "http://127.0.0.1:8848/nacos/v1/ns/instance/list?serviceName=order-service&clusters=cluster-a" \
| jq '.hosts[] | {ip,port,clusterName,healthy}'

订阅推送机制#

Nacos 采用长轮询与推送结合,实现高效通知。

1. 长轮询订阅(机制示意)#

sequenceDiagram
  participant C as Client
  participant S as Nacos Server
  C->>S: Long Polling 订阅服务(order-service)
  alt 有变更
    S-->>C: 返回变更结果
  else 无变更
    S-->>C: 超时返回(无变更)
  end
  C->>S: 重新发起订阅

2. 变更推送与本地更新#

  • 实例上线/下线或健康变化触发变更事件
  • 订阅客户端收到响应并更新本地缓存
  • 业务调用优先使用缓存

示例:模拟变更触发推送#

# 1) 注册一个实例
curl -X POST "http://127.0.0.1:8848/nacos/v1/ns/instance" \
  -d "serviceName=order-service" \
  -d "ip=10.0.0.21" \
  -d "port=8081" \
  -d "weight=1" \
  -d "healthy=true" \
  -d "clusterName=cluster-a"

# 2) 取消注册该实例,触发变更
curl -X DELETE "http://127.0.0.1:8848/nacos/v1/ns/instance" \
  -d "serviceName=order-service" \
  -d "ip=10.0.0.21" \
  -d "port=8081"

# 预期效果:订阅该服务的客户端收到变更通知并更新缓存

客户端缓存策略#

  • 内存缓存:快速读取
  • 本地磁盘缓存:注册中心不可用时回退
  • 过期机制:避免长期使用过期实例

示例:查看本地缓存文件(常见路径)#

# 以 Java SDK 为例,缓存路径常见于用户目录
ls -lh ~/.nacos/naming/

# 预期效果:看到以服务名命名的缓存文件

推送与拉取的平衡#

  • 推送优先:实时性强
  • 定时拉取兜底:推送异常时保证最终一致性
  • 一致性保证:长轮询与定时拉取结合

示例:定时拉取脚本(排障/验证)#

#!/usr/bin/env bash
# 文件: /opt/nacos/tools/pull_instances.sh
# 作用: 每10秒拉取一次服务实例列表,便于验证推送是否异常
while true; do
  echo "== $(date) =="
  curl -s "http://127.0.0.1:8848/nacos/v1/ns/instance/list?serviceName=order-service" \
  | jq '.hosts[] | {ip,port,healthy,weight}'
  sleep 10
done

排错要点(含命令)#

  1. 订阅未生效
    - 检查客户端是否配置 namespace/group/cluster 一致
    - 检查 Nacos 是否健康
# 查看 Nacos 健康
curl -s "http://127.0.0.1:8848/nacos/v1/console/health" | jq '.'
  1. 变更未推送
    - 检查实例是否正确注册
# 列出服务实例验证
curl -s "http://127.0.0.1:8848/nacos/v1/ns/instance/list?serviceName=order-service" | jq '.hosts'
  1. 客户端缓存异常
    - 清理本地缓存重试
rm -rf ~/.nacos/naming/*
# 预期效果:客户端重新拉取并生成缓存
  1. 服务不健康导致不可用
    - 核实健康状态与心跳
# 强制将实例置为健康(仅用于测试)
curl -X PUT "http://127.0.0.1:8848/nacos/v1/ns/instance" \
  -d "serviceName=order-service" \
  -d "ip=10.0.0.21" \
  -d "port=8081" \
  -d "healthy=true"

练习#

  1. 使用 OpenAPI 注册 2 个实例,验证订阅客户端收到变更。
  2. 手动删除缓存文件,观察客户端重新拉取时间与日志变化。
  3. 编写脚本每 5 秒拉取实例列表,并在实例下线时输出告警信息。