Nacos - 服务注册

Nacos 的服务注册是其核心功能之一。随着版本的演进,Nacos 经历了从 1.x(基于 HTTP)到 2.x(基于 gRPC)的架构升级。

下面我将从客户端发送请求服务端处理请求心跳维持与健康检查三个维度,详细讲解 Nacos(以 2.x 版本为主,兼顾 1.x 区别)的服务注册流程。


一、 整体流程概览

  1. 服务启动:客户端(微服务)启动,读取配置。
  2. 建立连接:客户端与 Nacos 服务端建立长连接(gRPC)。
  3. 发送注册请求:客户端封装实例信息(IP、Port、服务名等)发送给服务端。
  4. 服务端存储:服务端将实例信息存入内存注册表。
  5. 数据同步:服务端将新注册的实例信息同步给集群内的其他 Nacos 节点(Distro 协议)。
  6. 服务变更通知:服务端主动推送最新的服务列表给订阅了该服务的客户端。

二、 详细步骤解析

1. 客户端:发起注册 (Client Side)

  • 入口 :在 Spring Cloud 环境下,注册入口是 NacosServiceRegistry.register() 方法。
  • 封装实例 :构造 Instance 对象,包含:
    • Service Name(服务名)
    • IPPort
    • Weight(权重)
    • Metadata(元数据)
    • Ephemeral(是否是临时实例,默认 true
  • 通信协议
    • Nacos 1.x :通过 HTTP POST 请求发送到 /nacos/v1/ns/instance
    • Nacos 2.x :通过 gRPC 传输。客户端通过 NamingClientProxy 调用 registerService,请求会被封装成 InstanceRequest 发送。

2. 服务端:接收与存储 (Server Side)

当 Nacos 服务端收到注册请求后,会执行以下逻辑:

  • 解析请求InstanceRequestHandler 接收 gRPC 请求(1.x 是 InstanceController)。
  • 内存注册表维护
    • Nacos 内部维护了一个多层的 Map 结构: Map<namespace, Map<group::serviceName, Service>>
    • Service 类中包含多个 Cluster(集群)。
    • Cluster 中维护了两个 Set<Instance>:一个是 临时实例 ,一个是 持久化实例
  • 写时复制 (CopyOnWrite) :为了防止高并发下的读写冲突,Nacos 在更新实例列表时采用了类似 CopyOnWrite 的机制。它会先读取旧的列表,创建一个新列表,把新实例放进去,最后替换旧列表。

3. 服务端:一致性协议 (Consistency)

Nacos 根据实例类型(临时/持久化)走不同的协议:

  • 临时实例(默认,AP模式)
    • 使用 Distro 协议(Nacos 自研)。
    • 注册节点会立即同步给集群内其他节点。
    • 遵循 最终一致性,保证高可用。
  • 持久化实例(CP模式)
    • 使用 Raft 协议(JRaft 实现)。
    • 必须过半数节点写入成功才算注册成功。
    • 保证 强一致性

4. 服务端:推送通知 (Push)

  • 一旦注册表发生变化,服务端会触发 ServiceChangeEvent
  • 推送机制 :服务端通过 PushService 找到所有订阅了该服务的客户端,通过 gRPC(2.x)或 UDP(1.x)将最新的实例列表推送过去。
  • 客户端缓存 :客户端收到更新后,会更新本地的 ServiceInfo 缓存,从而实现负载均衡时拿到最新的地址。

三、 核心:健康检查机制

注册流程完成后,如何保证服务一直"在线"?

  1. Nacos 1.x (HTTP + 心跳)

    • 客户端每隔 5秒 发送一次心跳(Beat)。
    • 服务端若 15秒 没收到心跳,标记为不健康。
    • 30秒 没收到心跳,直接剔除实例。
  2. Nacos 2.x (gRPC + 连接探测)

    • 长连接 :基于 gRPC 的 Stream。如果客户端宕机,gRPC 连接会断开。
    • 连接断开即剔除:服务端监控连接状态,一旦连接异常断开(Connection Disconnect),服务端会立即触发下线流程(针对临时实例)。这种方式比心跳更实时。

四、 总结: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 的长连接状态来维持实例的健康状态,一旦断开则自动剔除。"

相关推荐
曹牧2 小时前
Spring Boot:如何测试Java Controller中的POST请求?
java·开发语言
KYGALYX3 小时前
服务异步通信
开发语言·后端·微服务·ruby
爬山算法3 小时前
Hibernate(90)如何在故障注入测试中使用Hibernate?
java·后端·hibernate
kfyty7253 小时前
集成 spring-ai 2.x 实践中遇到的一些问题及解决方案
java·人工智能·spring-ai
猫头虎3 小时前
如何排查并解决项目启动时报错Error encountered while processing: java.io.IOException: closed 的问题
java·开发语言·jvm·spring boot·python·开源·maven
李少兄3 小时前
在 IntelliJ IDEA 中修改 Git 远程仓库地址
java·git·intellij-idea
忆~遂愿4 小时前
ops-cv 算子库深度解析:面向视觉任务的硬件优化与数据布局(NCHW/NHWC)策略
java·大数据·linux·人工智能
小韩学长yyds4 小时前
Java序列化避坑指南:明确这4种场景,再也不盲目实现Serializable
java·序列化
仟濹4 小时前
【Java基础】多态 | 打卡day2
java·开发语言
Re.不晚4 小时前
JAVA进阶之路——无奖问答挑战2
java·开发语言