基于本文回答

播面 播面

文图音视,全方位拆解八股文
0
评论

Nacos 客户端是如何感知配置变更的?

知识点图片

Nacos 客户端感知配置变更的核心机制可以概括为:“客户端长轮询(Long Polling)”(针对 Nacos 1.x HTTP 协议)和 “gRPC 双向流”(针对 Nacos 2.x)。

其中,长轮询是 Nacos 最经典的设计,它结合了 Push(推送)和 Pull(拉取)的优点。

以下是详细的原理分析:


1. 核心机制:长轮询 (Long Polling)

在 Nacos 1.x 版本(以及 2.x 兼容模式)中,客户端并不是简单地定时“拉”数据,也不是服务器主动建立长连接“推”数据,而是采用了长轮询

流程步骤:

  1. 客户端发起请求
    客户端(ClientWorker)发起一个 HTTP 请求给服务端,询问:“配置有没有变化?”。这个请求的超时时间设置得很长(默认 30 秒)。

  2. 服务端“挂起”请求
    服务端收到请求后,不会立即返回结果。

    • 它会检查客户端传来的配置 MD5 与服务端的 MD5 是否一致。
    • 如果有变化:立即返回最新的配置信息。
    • 如果没有变化:服务端利用 Servlet 3.0 的异步机制(AsyncContext),将这个 HTTP 请求“挂起”(Hold 住),暂时不响应,放入一个队列中。
  3. 等待变更或超时
    服务端会保持这个连接打开,直到以下任一情况发生:

    • 情况 A:配置发生变更(用户在控制台修改了配置)。服务端触发事件,找到挂起的请求,立即将变更的配置 ID 返回给客户端。
    • 情况 B:超时(约 29.5秒)。如果在等待期间一直没有配置变更,为了防止连接超时断开,服务端会在 29.5 秒左右(略小于客户端设置的 30 秒)自动返回一个“无变更(304)”的响应。
  4. 客户端处理响应

    • 如果收到配置变更的响应,客户端会立即发起一次普通的 GET 请求,拉取具体的配置内容,更新本地缓存,并触发用户注册的监听器(Listener)。
    • 如果收到无变更响应,客户端会立即再次发起下一个长轮询请求,周而复始。

优点:这种方式既保证了配置变更的实时性(类似 Push),又避免了服务端维护大量长连接的资源消耗(类似 Pull 的无状态特性),同时减少了无效的网络交互。


2. Nacos 2.x 的升级:gRPC 长连接

从 Nacos 2.0 开始,为了提升性能和连接数支持,底层协议从 HTTP 升级为了 gRPC

  • 机制:客户端与服务端建立持久化的 gRPC 长连接。
  • 感知方式
    • 客户端注册监听器到服务端。
    • 当服务端配置发生变更时,服务端通过 gRPC 的双向流(Bi-Directional Stream)主动将变更推送到客户端。
    • 这种方式比 HTTP 长轮询更加高效,延迟更低,且减少了频繁建立 HTTP 连接的开销。

3. 客户端内部工作流程 (ClientWorker)

无论是 HTTP 还是 gRPC,Nacos 客户端内部都有一个核心组件 ClientWorker 来管理这一过程。以下是更细致的内部逻辑:

  1. 分片检查:如果客户端监听了大量的配置(例如几千个),Nacos 会将这些配置分成多个任务块(CacheData),每个任务块最多包含 3000 个配置 ID。
  2. 线程池调度ClientWorker 维护一个线程池,定期执行长轮询任务。
  3. MD5 比对
    • 客户端请求时,会将本地缓存的配置指纹(MD5)带给服务端。
    • 服务端比对 MD5,只有 MD5 不一致时才认为有变更。
  4. 双重保险(容灾)
    • 内存缓存:客户端内存中有一份配置缓存。
    • 本地文件快照:Nacos 客户端会将拉取到的配置在本地磁盘(通常是 ~/nacos/config 目录下)保存一份快照。
    • 作用:当 Nacos 服务端彻底宕机时,客户端可以降级读取本地文件,保证应用能启动或运行。

总结

Nacos 客户端感知配置变更的过程可以概括为:

  1. 客户端启动一个线程,不断向服务端发起长轮询请求(或建立 gRPC 流)。
  2. 服务端利用异步机制Hold 住请求,直到配置更新或超时。
  3. 一旦配置变更,服务端立即返回变更的 DataID。
  4. 客户端收到变更通知后,拉取最新配置,更新本地缓存和文件,并回调用户的 Listener。
00:00
00:00