服务注册与发现: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(以官方最新稳定版为准),解压后启动
把一个服务注册到 Nacos
加依赖、加注解、写配置,三步。Spring Cloud 2023 之后,@EnableDiscoveryClient 注解已经不是必须的了——只要 classpath 里有 Nacos 依赖,服务启动时自动注册。
第一步:在服务模块的 pom.xml 里加 Nacos 发现依赖
第二步:application.yml 里告诉服务"注册中心在哪"
第三步:启动类(新版 Spring Cloud 不写 @EnableDiscoveryClient 也能注册)
很多人注册成功了,但用 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 切换。新项目首选。 |
| Eureka | Netflix 老一代,已停更,AP 模型。老项目维护时能见到。 |
| Consul / ZooKeeper | Consul 偏服务网格生态;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 内部自动做了这件事。