Nacos 的服务注册是其核心功能之一。随着版本的演进,Nacos 经历了从 1.x(基于 HTTP)到 2.x(基于 gRPC)的架构升级。
下面我将从客户端发送请求 、服务端处理请求 、心跳维持与健康检查三个维度,详细讲解 Nacos(以 2.x 版本为主,兼顾 1.x 区别)的服务注册流程。
一、 整体流程概览
- 服务启动:客户端(微服务)启动,读取配置。
- 建立连接:客户端与 Nacos 服务端建立长连接(gRPC)。
- 发送注册请求:客户端封装实例信息(IP、Port、服务名等)发送给服务端。
- 服务端存储:服务端将实例信息存入内存注册表。
- 数据同步:服务端将新注册的实例信息同步给集群内的其他 Nacos 节点(Distro 协议)。
- 服务变更通知:服务端主动推送最新的服务列表给订阅了该服务的客户端。
二、 详细步骤解析
1. 客户端:发起注册 (Client Side)
- 入口 :在 Spring Cloud 环境下,注册入口是
NacosServiceRegistry.register()方法。 - 封装实例 :构造
Instance对象,包含:Service Name(服务名)IP和PortWeight(权重)Metadata(元数据)Ephemeral(是否是临时实例,默认 true)
- 通信协议 :
- Nacos 1.x :通过 HTTP POST 请求发送到
/nacos/v1/ns/instance。 - Nacos 2.x :通过 gRPC 传输。客户端通过
NamingClientProxy调用registerService,请求会被封装成InstanceRequest发送。
- Nacos 1.x :通过 HTTP POST 请求发送到
2. 服务端:接收与存储 (Server Side)
当 Nacos 服务端收到注册请求后,会执行以下逻辑:
- 解析请求 :
InstanceRequestHandler接收 gRPC 请求(1.x 是InstanceController)。 - 内存注册表维护 :
- Nacos 内部维护了一个多层的 Map 结构:
Map<namespace, Map<group::serviceName, Service>> Service类中包含多个Cluster(集群)。Cluster中维护了两个Set<Instance>:一个是 临时实例 ,一个是 持久化实例。
- Nacos 内部维护了一个多层的 Map 结构:
- 写时复制 (CopyOnWrite) :为了防止高并发下的读写冲突,Nacos 在更新实例列表时采用了类似 CopyOnWrite 的机制。它会先读取旧的列表,创建一个新列表,把新实例放进去,最后替换旧列表。
3. 服务端:一致性协议 (Consistency)
Nacos 根据实例类型(临时/持久化)走不同的协议:
- 临时实例(默认,AP模式) :
- 使用 Distro 协议(Nacos 自研)。
- 注册节点会立即同步给集群内其他节点。
- 遵循 最终一致性,保证高可用。
- 持久化实例(CP模式) :
- 使用 Raft 协议(JRaft 实现)。
- 必须过半数节点写入成功才算注册成功。
- 保证 强一致性。
4. 服务端:推送通知 (Push)
- 一旦注册表发生变化,服务端会触发
ServiceChangeEvent。 - 推送机制 :服务端通过 PushService 找到所有订阅了该服务的客户端,通过 gRPC(2.x)或 UDP(1.x)将最新的实例列表推送过去。
- 客户端缓存 :客户端收到更新后,会更新本地的
ServiceInfo缓存,从而实现负载均衡时拿到最新的地址。
三、 核心:健康检查机制
注册流程完成后,如何保证服务一直"在线"?
-
Nacos 1.x (HTTP + 心跳):
- 客户端每隔 5秒 发送一次心跳(Beat)。
- 服务端若 15秒 没收到心跳,标记为不健康。
- 若 30秒 没收到心跳,直接剔除实例。
-
Nacos 2.x (gRPC + 连接探测):
- 长连接 :基于 gRPC 的
Stream。如果客户端宕机,gRPC 连接会断开。 - 连接断开即剔除:服务端监控连接状态,一旦连接异常断开(Connection Disconnect),服务端会立即触发下线流程(针对临时实例)。这种方式比心跳更实时。
- 长连接 :基于 gRPC 的
四、 总结:1.x 与 2.x 的关键区别
| 特性 | Nacos 1.x | Nacos 2.x |
|---|---|---|
| 通信协议 | HTTP | gRPC (双向流) |
| 注册效率 | 每次注册/心跳都是短连接,开销大 | 长连接复用,极大减少连接握手消耗 |
| 实时性 | 依赖心跳间隔,响应稍慢 | 连接断开瞬时感应,响应极快 |
| 一致性协议 | Distro (AP) / Raft (CP) | 优化后的 Distro / JRaft |
总结口述版:
"Nacos 注册流程首先是客户端通过 gRPC(2.x)向服务端发起注册请求。服务端接收后,会将实例信息存入内存中的双层 Map 结构中,并根据实例是否是临时的,选择走 Distro 异步同步(AP)或 Raft 强一致同步(CP)。存储完成后,服务端会发布变更事件,通过长连接异步推送给所有订阅该服务的客户端。最后,通过 gRPC 的长连接状态来维持实例的健康状态,一旦断开则自动剔除。"