Nacos - 服务发现

Nacos 的服务发现(Service Discovery)是指服务消费者(Consumer)如何获取服务提供者(Provider)地址列表的过程。

Nacos 采用了 "主动拉取 + 被动推送" 相结合的机制,确保了服务发现的实时性高可用性


一、 服务发现的整体架构

服务发现主要涉及三个角色:

  1. 服务提供者 (Provider):注册自己的 IP/端口到 Nacos。
  2. Nacos Server:保存服务注册表,并感知实例状态变化。
  3. 服务消费者 (Consumer):从 Nacos 获取地址列表,并监听变化。

二、 详细流程详解

1. 消费者初始化与订阅 (Subscription)

当一个微服务启动并需要调用其他服务时:

  • 查询缓存:消费者首先会检查本地内存中是否有目标服务的实例列表。
  • 发起订阅:如果没有或需要更新,消费者会向 Nacos Server 发起订阅请求(Subscribe)。
  • 版本差异
    • Nacos 1.x:通过 HTTP 轮询定时拉取,并开启一个 UDP 端口接收服务端的推送。
    • Nacos 2.x :通过 gRPC 双向流 建立长连接。客户端发送 ServiceQueryRequest,并在服务端注册该连接的订阅关系。

2. 服务端获取与过滤 (Server Side)

Nacos Server 收到查询请求后:

  • 检索注册表 :从内存 Map(Service -> Cluster -> Instances)中找到对应的实例。
  • 健康检查过滤
    • 只返回 healthy=true(健康)的实例。
    • 只返回 enabled=true(启用)的实例。
  • 选择集群:根据客户端配置的集群名称(Cluster Name),优先返回同集群的实例(就近访问策略)。

3. 客户端本地缓存 (Local Cache)

这是 Nacos 保证高可用的关键:

  • 内存缓存 :客户端将获取到的 ServiceInfo(包含实例列表)保存到内存中的 ServiceInfoHolder
  • 磁盘缓存 :同时将数据异步写入本地磁盘文件(路径通常在 ${user.home}/nacos/naming/${namespace})。
  • 容灾逻辑 :如果 Nacos Server 全部宕机,消费者会直接读取本地磁盘文件,保证业务不中断。

4. 实时更新机制 (Push & Pull)

为了保证消费者拿到的地址是最新的,Nacos 采用了以下策略:

  • 被动接收推送 (Push)
    • 一旦服务提供者下线、故障或有新节点加入,Nacos Server 会触发 ServiceChangeEvent
    • Nacos 2.x 会通过已建立的 gRPC 长连接,主动将最新的实例列表推送到消费者(Push)。这种方式是毫秒级的。
  • 定时主动拉取 (Pull)
    • 作为补偿机制,客户端内部有一个定时任务(默认每 10 秒或根据配置),会检查本地数据的版本,必要时重新拉取,防止因网络闪断导致的推送丢失。

5. 客户端负载均衡 (Load Balance)

服务发现拿到的是一个列表(比如 3 个 IP),具体调用哪一个由客户端决定:

  • 在 Spring Cloud 环境中,通常配合 Spring Cloud LoadBalancerRibbon
  • 根据 Nacos 返回的 Weight(权重) 进行加权随机访问。
  • 执行最终的 RPC 调用(如 RestTemplate, Feign, Dubbo)。

三、 核心流程图解

  1. Consumer -> query (gRPC) -> Nacos Server
  2. Nacos Server -> result (Instance List) -> Consumer
  3. Consumer -> save -> Memory & Disk Cache
  4. (当 Provider 发生变化时)
  5. Nacos Server -> push (New List) -> Consumer
  6. Consumer -> update -> Local Cache

四、 关键特性总结

特性 说明
实时性 2.x 基于 gRPC 长连接推送,几乎瞬时感知服务变化。
高可用 (Self-Protection) 就算 Nacos 集群挂了,客户端靠本地缓存(磁盘文件)也能正常调用服务。
就近访问 支持按 Cluster 归类,优先调用同机房/同地域的服务,降低延迟。
权重调整 支持在 Nacos 控制台动态修改实例权重,实现灰度发布或平滑下线。

五、 Nacos 是如何支撑大规模服务发现的?

  1. 分级存储:Namespace -> Group -> Service -> Cluster -> Instance,结构清晰。
  2. UDP/gRPC 推送:相比全量拉取,推送极大减少了网络带宽消耗。
  3. 写时复制 (CopyOnWrite):在更新实例列表时,不影响读取操作,保证高性能。
  4. 压缩传输:在返回大量实例时,Nacos 会对数据进行压缩,减少网络开销。
相关推荐
微露清风14 小时前
系统性学习C++-第十八讲-封装红黑树实现myset与mymap
java·c++·学习
dasi022714 小时前
Java趣闻
java
阿波罗尼亚15 小时前
Tcp SSE Utils
android·java·tcp/ip
susu108301891115 小时前
springboot3.5.8整合minio8.5.9
java·springboot
不知道累,只知道类15 小时前
深入理解 Java 虚拟线程 (Project Loom)
java·开发语言
myzshare15 小时前
实战分享:我是如何用SSM框架开发出一个完整项目的
java·mysql·spring cloud·微信小程序
Chan1616 小时前
【 Java八股文面试 | JavaSE篇 】
java·jvm·spring boot·面试·java-ee·八股
wen__xvn16 小时前
代码随想录算法训练营DAY10第五章 栈与队列part01
java·前端·算法
独自破碎E16 小时前
解释一下NIO、BIO、AIO
java·开发语言·nio