Nacos注册中心原理

一、核心架构图示

复制代码
![](https://i-blog.csdnimg.cn/direct/74fd8d9a8b6844fcb13d972ebbdf6996.png)

二、关键技术流程详解

1. 服务注册阶段

  • 实现原理:服务启动时将元数据(服务名、实例ID、端点地址)封装成instance对象向注册中心发起POST请求
  • 关键参数:
java 复制代码
# 示例配置(Spring Boot)
spring:
cloud:
inetutils:
preferred-networks: 192.168.1.0/24 # IP过滤规则
instance-id: ${spring.application.name}:${server.port}
1.1 注册存储

在Nacos Server(注册中心)接收到请求后:

1)将服务实例信息持久化到内存数据库(基于Raft协议的nacos/nacos-cluster模块)

2)同步更新到本地文件系统(snapshot机制)

3)构建服务实例索引(按服务名+分组归类)

2. 服务发现阶段

  • 订阅机制:
  • 长连接:WebSocket保持实时通信
  • 短轮询:HTTP GET /services/{serviceName} 定期拉取
  • 缓存策略:
java 复制代码
// 客户端缓存实现示例
public class ServiceCache {
private Map<String, List<ServiceInstance>> cache = new ConcurrentHashMap<>();

@Scheduled(fixedDelay = 30000)
public void refreshCache() {
cache.putAll(registryClient.getServices());
    }
}

3. 心跳续约机制

服务提供者在注册中心完成注册之后与注册中心会建立长连接:

1)服务实例每5秒发送一次心跳(默认间隔)

2)注册中心通过TCP长连接(默认端口7848)接收心跳

3)心跳超时时间默认15秒,超时实例将被剔除

3.1 如何处理心跳请求?
  • 注册中心接收到服务提供者的心跳请求,接着解析请求中的Instance对象并执行以下核心操作:

(1) 实例注册校验

若服务实例不存在:立即异步注册

若已存在:更新最后心跳时间

(2) 状态维护

自动恢复非健康实例为健康状态

(3) 异步处理

启动独立线程执行注册/更新操作,避免阻塞主流程

  • 注册中心注册表维护机制

(1)注册表的数据结构

使用ConcurrentHashMap分级存储:Map<命名空间, Map<分组:服务名, Service对象>>

(2)持久化策略

|------|------------|------------------------------|
| 模式 | 协议 | 触发条件 |
| CP模式 | 基于Raft协议 | * 需集群半数以上节点确认写入 * 数据同步至内存和磁盘 |
| AP模式 | 基于Distro协议 | * 异步批量同步至其他节点 * 优先保证可用性 |

4. 负载均衡策略

以下是 Nacos 客户端(服务调用者)常用的负载均衡策略对比表:

策略名称 核心原理 适用场景 优点 缺点 配置示例
轮询(Round Robin)​ 按顺序依次选择实例(如实例列表为 A,B,C,依次选择 A→B→C→A...) 实例性能相近的简单场景 实现简单,请求均匀分布 忽略实例实际负载差异 LoadBalancerClient.setRule(new RoundRobinRule())
随机(Random)​ 从实例列表中随机选择一个实例 实例性能差异不大的高并发场景 无状态,实现简单 可能导致某些实例过载 new RandomRule()
加权轮询(Weighted Round Robin)​ 根据实例权重分配请求(权重高的实例被选中概率更高) 实例配置差异明显的场景(如不同规格服务器) 灵活应对实例性能差异 需手动配置权重 new WeightedResponseTimeRule()
最少连接(Least Connections)​ 优先选择当前连接数最少的实例 长连接服务(如数据库、WebSocket) 动态感知实例负载 需维护连接数状态 new LeastConnectionsRule()
响应时间权重(Response Time Weighted)​ 根据实例平均响应时间动态计算权重(响应越快,权重越高) 对延迟敏感的服务调用 自动优化用户体验 需持续监控响应时间 new BestAvailableRule()
一致性哈希(Consistent Hashing)​ 通过哈希环将请求映射到固定实例,相同参数的请求总是路由到同一实例(会话粘滞) 需保持会话状态的服务(如购物车) 避免缓存失效,减少热点问题 实例扩缩容时哈希抖动 new ConsistentHashRule()

​补充说明

  1. 默认策略 :Nacos 默认使用 加权轮询(结合实例健康状态和响应时间动态调整权重)。

  2. 扩展性 :可通过实现 IRule 接口自定义策略(如基于 CPU/内存利用率的动态权重算法)。

  3. 配置方式 :在 Spring Cloud 中可通过 application.yml 配置:

    java 复制代码
    spring:
      cloud:
        loadbalancer:
          ribbon:
            NFLoadBalancerRuleClassName: com.netflix.loadbalancer.WeightedResponseTimeRule

选择建议:中小规模服务优先使用默认加权轮询;对延迟敏感场景选择响应时间权重;需要会话粘滞时选一致性哈希。

三、技术选型对比矩阵

特性 Consul Eureka Nacos
协议支持 HTTP/gRPC HTTP HTTP/gRPC
一致性模型 CP AP CP+AP
配置中心 内置 需独立部署 内置
部署复杂度 中等(需etcd) 简单(纯Java) 简单(Spring Cloud集成)

实施建议:中小规模系统推荐使用Nacos(简化运维),金融级系统建议Consul+Istio组合(强一致性+服务网格)。关键业务系统务必配置健康检查熔断机制,建议心跳超时时间设置为30s-60s,重试次数不超过3次。

四、思考

此时你的服务提供者其中有一个服务挂掉了,这时候其注册中心和调用者会怎么做呢?

情况一:服务提供者在销毁时间前恢复

1. 服务提供者动作

  • 重启并恢复心跳:服务提供者进程重启后,重新向 Nacos Server 发送心跳请求(PUT 接口),携带自身实例信息(IP、端口、服务名等)。

2. 注册中心(Nacos Server)动作

  • 接收心跳请求:Nacos Server 收到心跳后,检查实例状态:
  • 若实例此前被标记为 非健康 ,则将其状态更新为 健康。
  • 若实例此前已被 注销(超过销毁时间),则忽略此次心跳(视为无效恢复)。
  • 触发健康状态更新事件 :通过 UDP 通信 向所有订阅该服务的客户端广播服务实例状态变更事件(如 InstanceStatusChangedEvent)。
  • 持久化存储更新:若启用 CP 模式(Raft 协议),更新 Raft 日志并同步到集群半数以上节点;若为 AP 模式(Distro 协议),异步更新内存并广播增量数据。

3. 调用者动作

  • 接收事件通知 :客户端通过 UDP 监听收到实例状态变更事件(如 InstanceStatusChangedEvent)。

  • 更新本地缓存:将恢复健康的实例重新加入负载均衡候选池。

  • 后续调用逻辑:下次发起请求时,负载均衡器(如 Ribbon)会基于最新实例列表选择健康实例(包括刚恢复的实例)。

情况二:服务提供者在销毁时间后恢复

1. 服务提供者动作

  • 超时后重启 :服务提供者因宕机超过销毁时间(如 Nacos 配置的 ephemeralTTL 或默认 30 秒),实例已被注册中心移除。
  • 重新注册 :进程重启后,向 Nacos Server 发送 POST 请求 触发全新注册(而非恢复旧实例)。

2. 注册中心(Nacos Server)动作

  • 处理新注册请求:
  • 将实例信息封装为新的 Instance 对象。
  • 创建异步任务写入注册表(CP 模式需 Raft 半数节点确认,AP 模式直接写入内存并向集群广播)。
  • 推送全量服务列表 :通过 UDP 向客户端(调用者)广播服务实例变更事件 (如 ServiceChangeEvent),通知所有订阅者该服务实例已重新加入集群。

3. 调用者动作

  • 接收全量更新事件 :客户端收到事件后,触发 本地缓存刷新(通过定时拉取或 UDP 事件驱动)。
  • 移除旧实例:本地缓存中已不存在超时的旧实例,新注册的实例作为独立实体加入服务列表。
  • 负载均衡调整:后续调用会基于最新服务列表(包含新注册实例)进行路由。
相关推荐
欢醉3 天前
踩坑记:一次Nacos客户端偶发connect timed out全链路排查
nacos·springcloud
Rain的Java大神之路3 天前
如何快速上传10G文件
java·spring boot·redis·后端·mysql·spring cloud·面试
需要8264 天前
MySQL 索引 B+ 树与“查询为什么变慢了
java·spring boot·spring·spring cloud·tomcat
需要8264 天前
Arthas 一个命令排查线上问题
java·jvm·spring·spring cloud
苏渡苇5 天前
Spring Insight 里如何把 Span 画成瀑布时间线
后端·spring·spring cloud·springboot·监控·apm
叶总没有会5 天前
Nacos—注册中心
spring cloud·微服务
cnkeysky5 天前
SpringBoot 整合 nacos 配置中心
nacos·springboot
cnkeysky6 天前
docker 运行 nacos
docker·nacos
苏渡苇6 天前
Spring Insight 里如何把 Span 收成一条链路
spring boot·spring·spring cloud·系统监控·apm
叶总没有会6 天前
微服务--分布式基础
java·spring·spring cloud·微服务