nacos

Nacos 本身并不会主动去发现服务,而是服务启动时主动向 Nacos 注册,消费者再从 Nacos 拉取服务列表并订阅变化,从而实现服务发现。

下面按照整个流程来介绍。


一、什么是服务注册和服务发现

假设有两个服务:

 
Order-Service
User-Service
 

Order 调用 User。

如果没有注册中心:

 
Order -----> http://192.168.1.5:8080
 

IP一旦变化:

 
Order 配置全部修改
 

非常麻烦。

有了 Nacos:

 
           Nacos
             |
   -------------------
   |                 |
User-1          User-2

Order
 

Order只需要问Nacos:

User-Service在哪?

Nacos返回:

 
User-Service

192.168.1.5:8080
192.168.1.8:8080
192.168.1.9:8080
 

然后Order自己选择一个去调用。

这就是服务发现(Service Discovery)


二、服务注册(Service Register)

例如:

 
User-Service
 

启动时。

Spring Cloud Alibaba 自动完成以下事情:

 
ApplicationContext启动

        ↓

NacosAutoServiceRegistration

        ↓

获取本机信息

IP
PORT
服务名

        ↓

调用NamingService.registerInstance()

        ↓

HTTP请求

POST
/v1/ns/instance

        ↓

Nacos Server
 

例如:

注册的数据:

 
serviceName=user-service

ip=192.168.1.5

port=8081

weight=1

cluster=DEFAULT

healthy=true
 

Nacos收到以后,保存到内存。

例如:

 
user-service

    |
    +------192.168.1.5:8081
 

如果再启动一个:

 
192.168.1.6:8081
 

变成:

 
user-service

    |
    +------192.168.1.5
    |
    +------192.168.1.6
 

这就是服务注册。


三、Nacos保存在哪里?

Nacos实际上维护了一张大的注册表。

可以理解成:

 
Map<
    ServiceName,
    List<Instance>
>
 

例如:

 
{
  "user-service":[
      192.168.1.5:8081,
      192.168.1.6:8081
  ],

  "order-service":[
      192.168.1.10:8082
  ]
}
 

实际上源码中维护的是类似:

 
namespace

    ↓

group

    ↓

service

    ↓

cluster

    ↓

instance
 

层级。


四、服务发现(Discovery)

Order启动以后:

 
Ribbon

OpenFeign

LoadBalancer
 

都会调用:

 
NamingService.getAllInstances("user-service");
 

实际上就是:

 
GET

/v1/ns/instance/list
 

Nacos返回:

 
[
   {
      "ip":"192.168.1.5",
      "port":8081
   },
   {
      "ip":"192.168.1.6",
      "port":8081
   }
]
 

Spring Cloud收到以后放进本地缓存。

以后调用:

 
UserService
 

实际上就是:

 
192.168.1.5

或者

192.168.1.6
 

由负载均衡器决定。


五、如何知道服务上下线?

如果每次调用都请求Nacos:

 
Order

↓

Nacos

↓

User
 

效率太低。

所以:

Nacos采用"服务订阅(Subscribe)+ 推送(Push)"机制。

流程:

 
Order启动

        ↓

订阅user-service

        ↓

Nacos记录订阅关系
 

如果:

 
User3启动
 

注册:

 
registerInstance()
 

Nacos立即知道:

 
user-service

新增:

192.168.1.8
 

于是:

 
Push

↓

Order

↓

更新本地缓存
 

所以:

Order根本不用重新查询。


六、健康检查(Heartbeat)

如果:

 
User-Service
 

突然宕机。

Nacos怎么知道?

答案:

心跳机制。

客户端每隔:

 
默认5秒
 

发送:

 
Beat

POST

/v1/ns/instance/beat
 

内容:

 
service=user-service

ip=192.168.1.5

port=8081
 

Nacos更新时间:

 
lastBeat

2025-xx-xx
 

如果:

 
15秒
 

没有收到。

实例变成:

 
healthy=false
 

如果:

 
30秒
 

没有收到。

删除实例:

 
remove instance
 

于是:

 
Order收到Push

↓

删除该节点
 

七、服务发现为什么这么快?

因为:

消费者不会每次请求Nacos。

而是:

 
第一次:

Nacos

↓

获取全部实例

↓

本地缓存
 

之后:

 
调用

↓

本地缓存
 

实例变化:

 
Nacos Push

↓

更新缓存
 

所以:

真正访问Nacos的次数非常少。


八、负载均衡是如何工作的?

假设:

 
User

192.168.1.1

192.168.1.2

192.168.1.3
 

Spring Cloud LoadBalancer 获取实例列表:

 
List<ServiceInstance>
 

默认:

 
Round Robin
 

例如:

 
1

2

3

1

2

3
 

也可以自定义:

  • 随机(Random)
  • 权重(Weight)
  • 一致性哈希(Consistent Hash)
  • 最少连接(Least Connections,需要自行实现)

Nacos 本身也支持实例权重(Weight),客户端可以根据权重进行流量分配。


九、Nacos 注册与发现整体时序图

 
               +----------------------+
               |     Nacos Server     |
               +----------------------+
                    ▲            ▲
        注册实例     │            │ 查询/订阅服务
(registerInstance)  │            │ (getAllInstances/subscribe)
                    │            │
     +--------------+            +--------------+
     |                                         |
+-------------+                         +--------------+
| UserService |                         | OrderService |
+-------------+                         +--------------+
       │                                       │
       │ 心跳(默认5秒)                        │
       └──────────────► 更新实例状态            │
                       │                       │
      实例上下线变更 ◄─┴────── 推送(Push)─────┘
 

十、面试回答(2~3 分钟版本)

Nacos 的服务注册采用的是客户端主动注册模式。服务启动时,Spring Cloud Alibaba 会通过 NacosAutoServiceRegistration 收集当前实例的服务名、IP、端口、权重等信息,然后调用 Nacos 的 registerInstance 接口,将实例注册到 Nacos Server 中。Nacos 内部会按照 Namespace → Group → Service → Cluster → Instance 的层级维护服务实例列表。

服务发现时,服务消费者不会直接访问提供者,而是通过 NamingService.getAllInstances() 从 Nacos 获取目标服务的实例列表,并缓存到本地。之后实际调用由 Spring Cloud LoadBalancer 根据负载均衡策略(如轮询)从缓存中选择一个实例进行访问。

为了减少频繁查询注册中心的开销,Nacos 使用 订阅 + 推送(Push) 的机制。当服务实例上下线时,Nacos 会主动通知已订阅的消费者更新本地缓存,而不是每次请求都查询注册中心。

同时,服务实例会定期发送心跳(默认约每 5 秒一次)到 Nacos。若连续多个心跳周期未收到心跳,Nacos 会先将实例标记为不健康,持续超时后再将实例剔除,并通知订阅者更新服务列表。这种机制保证了服务注册、发现和故障摘除都能够较快完成。

posted on 2026-08-06 23:07  日思日睿  阅读(10)  评论(0)    收藏  举报