楼层: 首页/ 软件技术/ Spring Cloud 微服务/ 服务注册与发现:Nacos
二

服务注册与发现:Nacos

Service Registration & Discovery with Nacos

第一个灵魂问题:服务 A 怎么找到服务 B 的地址?单体里直接 localhost:8080 写死就行。微服务里服务 B 可能有 3 个实例,挂了一个自动扩容一个,IP 还经常变。你总不能把 B 的地址写死在 A 的代码里吧?这就需要一个"电话簿"——注册中心。

论注册中心怎么工作,三步讲明白

第一步,注册:每个服务启动时,主动跑到注册中心报到——"我叫 user-service,我在 192.168.1.10:8081"。注册中心把这个信息记在小本本上。

第二步,发现:服务 A 想调服务 B,不直接写 B 的 IP,而是问注册中心——"你知道 user-service 在哪吗?"注册中心返回一堆可用实例地址,A 自己挑一个发请求。

第三步,健康检查:注册中心定期给每个实例发"你还活着吗"的心跳,三分钟没回话就把它从小本本上划掉。服务 B 宕机了,A 下次问的时候就拿不到这个挂掉的地址了。

Nacos:阿里开源的注册中心 + 配置中心二合一,国内主流。Eureka 是 Spring Cloud Netflix 老一代产品,已停止维护,新项目别再用了,直接上 Nacos。

Nacos 安装与启动(Windows / Mac / Linux 通用)

Nacos 本质就是一个 Java 程序,下载解压就能跑。生产环境用集群模式,学习阶段单机模式足够。

第一步:从 GitHub 下载 Nacos Server(以官方最新稳定版为准),解压后启动

# 进入解压目录的 bin 文件夹 cd nacos/bin # 单机模式启动(Windows 用 startup.cmd -m standalone) sh startup.sh -m standalone # 看到 "Nacos started successfully" 就成了 # 默认端口 8848,控制台地址:http://localhost:8848/nacos # 默认账号密码:nacos / nacos(生产环境第一件事就是改密码)

把一个服务注册到 Nacos

加依赖、加注解、写配置,三步。Spring Cloud 2023 之后,@EnableDiscoveryClient 注解已经不是必须的了——只要 classpath 里有 Nacos 依赖,服务启动时自动注册。

第一步:在服务模块的 pom.xml 里加 Nacos 发现依赖

<dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId> </dependency> <!-- 负载均衡:调用 Nacos 上的服务时,需要 LoadBalancer 来挑实例 --> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-loadbalancer</artifactId> </dependency>

第二步:application.yml 里告诉服务"注册中心在哪"

server: port: 8081 # 这个服务自己跑在哪个端口 spring: application: name: user-service # 服务名,注册中心里就显示这个名字 cloud: nacos: discovery: server-addr: localhost:8848 # Nacos 地址,多个用逗号隔开 username: nacos password: nacos namespace: dev # 命名空间,下面讲多环境隔离用

第三步:启动类(新版 Spring Cloud 不写 @EnableDiscoveryClient 也能注册)

package com.example.user; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; // 老教程常让你写 @EnableDiscoveryClient,Spring Cloud 2023 起可省略 // 留着也不报错,只是没必要 @SpringBootApplication public class UserServiceApplication { public static void main(String[] args) { SpringApplication.run(UserServiceApplication.class, args); } }
服务调用方怎么拿到 Nacos 上的服务地址

很多人注册成功了,但用 RestTemplate 或 WebClient 写 http://user-service/xxx 时报错"未知主机"。原因是:默认情况下,RestTemplate 不会把 user-service 这个服务名翻译成真实 IP。你需要在 RestTemplate Bean 上加 @LoadBalanced 注解,它才会走 Nacos 的服务发现。这个下一章讲 OpenFeign 时还会遇到。

Eureka 与服务发现原理(老东西,混个眼熟)

老教程里满屏的 Eureka,新项目别用了,但面试和看老代码可能遇到,花两分钟了解一下。Eureka 是 Netflix 开源的注册中心,AP 模型(保可用,分区时牺牲一致性),2022 年左右停止维护,Spring Cloud 2020 之后已经移除。国内新项目清一色 Nacos(AP/CP 可切换)。

注册中心现状
Nacos阿里开源,国内主流,注册 + 配置二合一,支持 AP/CP 切换。新项目首选。
EurekaNetflix 老一代,已停更,AP 模型。老项目维护时能见到。
Consul / ZooKeeperConsul 偏服务网格生态;ZooKeeper 是 Hadoop 系老牌组件,做注册中心不是它的主业。

服务发现原理一句话:服务启动时往注册中心写自己的地址,调用方从注册中心读可用地址列表,本地用负载均衡算法挑一个发请求。注册中心把地址变化通过推送/长轮询通知给所有调用方,所以新实例上线、老实例下线,调用方秒级感知。

多环境隔离:dev / test / prod 别混在一个池子里

你本地开发的服务,不能注册到公司生产环境的 Nacos 上,不然调用方不小心调到你本地,把你自己电脑打挂。Nacos 用命名空间(namespace)做隔离,默认有一个 public 空间,自己再建 dev、test、prod。不同 namespace 的服务互相看不见。

概念大白话
Namespace最大的隔离单位,dev / test / prod 各一个,互相完全看不见。
Group 分组同一个 namespace 里再细分,比如按业务线分 order-group、pay-group。
Service具体的一个服务名,比如 user-service。

本章面试题

面试快答 · 服务注册与发现

Q1. 注册中心是 AP 还是 CP?Nacos 怎么选?

参考答案

Eureka 是 AP(分区时保可用、牺牲强一致);ZooKeeper 是 CP。Nacos 两者可切换:默认 AP(临时实例,适合做注册发现),切到 CP 模式用 Raft(适合需要强一致的配置场景)。注册发现选 AP——短暂拿不到一致地址比整个注册中心不可用好。

Q2. 服务 A 调服务 B,整个寻址流程是什么?

参考答案

B 启动时把地址注册到 Nacos;A 用 lb://user-service 调,LoadBalancer 从 Nacos 拉 B 的实例列表,本地按负载均衡(轮询)挑一个,发请求。Nacos 长轮询推送实例变更,A 秒级感知上下线。

Q3. 为什么 @LoadBalanced 是必须的?

参考答案

不加 @LoadBalanced,RestTemplate 把 user-service 当真实主机名解析,报"未知主机"。加了之后,它走拦截器把服务名翻译成 Nacos 上的真实 IP。OpenFeign 内部自动做了这件事。