基于本文回答

播面 播面

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

Nacos 消费者(Client)如何获取最新的服务列表?

知识点图片

Nacos 消费者(Client)获取最新服务列表的机制采用了 “推拉结合”(Push + Pull) 的策略。这种混合模式既保证了服务列表更新的实时性,又保证了数据的最终一致性和系统的健壮性。

具体来说,主要包含以下三个核心机制:

1. 定时拉取(Pull - 兜底机制)

这是客户端主动发起的行为,用于确保本地缓存与服务器端数据的最终一致性。

  • 机制: Nacos Client 内部有一个核心类 HostReactor,它会启动一个定时任务(UpdateTask)。
  • 频率: 默认情况下,每隔 10秒(可以通过配置调整),客户端会向 Nacos Server 发送 HTTP 请求(或 gRPC 请求),拉取订阅的服务列表。
  • 作用: 防止因网络抖动、推送失败等原因导致客户端长时间无法感知服务变化。这是一个“兜底”方案。

2. 实时感知(Push/Long Polling - 核心机制)

这是为了解决定时拉取延迟过高的问题(如果只靠10秒一次的拉取,服务下线后客户端感知会有延迟)。Nacos 1.x 和 2.x 在这方面的实现有较大区别:

Nacos 1.x:HTTP 长轮询 (Long Polling)

  • 原理: 客户端发起一个 HTTP 请求询问服务端“服务列表有没有变化?”
  • 服务端处理:
    • 如果有变化:服务端立即返回最新的服务列表。
    • 如果无变化:服务端不会立即返回,而是将该请求“挂起”(Hold 住),默认挂起约 30秒。
    • 如果在挂起期间发生了服务变更(如新实例注册),服务端会立即唤醒该请求并返回数据。
    • 如果挂起超时(30秒内无变化),服务端返回 304(未修改),客户端收到后再次发起长轮询。
  • 优点: 模拟了“推送”的效果,实时性很高(毫秒级),同时避免了建立大量长连接的开销(在 HTTP/1.1 时代)。

Nacos 2.x:gRPC 长连接 (真正的 Push)

  • 原理: Nacos 2.x 引入了 gRPC,客户端与服务端建立持久化的双向流式连接
  • 服务端处理: 当服务端感知到服务列表发生变更时,直接通过建立好的 gRPC 通道,主动将变更事件(NotifySubscriberRequest推送给客户端。
  • 优点: 相比 HTTP 长轮询,减少了 HTTP 请求头的开销,连接更稳定,实时性更强。

3. 本地缓存与容灾 (Local Cache)

客户端获取到服务列表后,不仅仅是放在内存里,还会进行持久化,以应对 Nacos Server 挂掉的极端情况。

  1. 内存缓存: 客户端将服务列表保存在内存中的 ServiceInfoMap 中,业务发起调用时,直接从内存读取,性能极高。
  2. 本地文件缓存(故障转移):
    • 客户端会将服务列表快照写入本地磁盘(通常在 ~/nacos/cache/ 目录下)。
    • 容灾场景: 当 Nacos Server 集群全部宕机,或者网络完全中断时,客户端会降级读取本地磁盘的缓存文件,确保服务调用不会立即瘫痪(虽然列表可能不是最新的,但比无法调用要好)。

总结:完整流程

  1. 启动时: Client 启动,主动向 Server 发起一次请求,拉取全量服务列表,填充本地内存和文件缓存。
  2. 运行时(实时更新):
    • 1.x: 开启 HTTP 长轮询,Server 有变动立即返回,无变动则等待。
    • 2.x: 建立 gRPC 连接,Server 有变动直接推送。
  3. 运行时(兜底): 每 10 秒执行一次定时拉取,校对数据,防止推送丢失。
  4. 故障时: 若连接 Server 失败,自动降级读取本地磁盘缓存。

这种设计使得 Nacos 既拥有 Zookeeper 般的实时性(通过推送/长轮询),又拥有 Eureka 般的可用性(通过本地缓存和定时拉取)。

00:00
00:00