[toc]
| 单词 | 词性 | 音标 | 含义 |
|---|---|---|---|
| register | v. | /ˈredʒɪstə(r)/ | 注册(服务启动时把自己(IP+端口)登记到注册中心) |
| discover | v. | /dɪˈskʌvə(r)/ | 发现(客户端从注册中心查询服务实例列表) |
| instance | n. | /ˈɪnstəns/ | 实例(一个运行中的服务进程,一个服务可多个实例) |
| heartbeat | n. | /ˈhɑːtbiːt/ | 心跳(实例定期向注册中心报告"我还活着") |
| health | n. | /helθ/ | 健康(注册中心根据心跳/健康检查判断实例是否可用) |
| provider | n. | /prəˈvaɪdə(r)/ | 服务提供者(对外提供服务接口的一方) |
| consumer | n. | /kənˈsjuːmə(r)/ | 服务消费者(调用别人接口的一方) |
Lecture03-SpringCloud-Nacos服务注册与发现
目标:先解决上一讲"IP 直连"暴露的痛点——启动 Nacos 注册中心,让"服务提供者注册、消费者发现",并让 Spring Boot 4 应用接入 Nacos,按服务名而不是 IP 调用。
1、为什么要注册中心
实例的 IP/端口会变(扩容、重启、迁移),不能写死在代码里。注册中心解决"服务在哪里":
- 服务提供者启动时注册:把
服务名 + IP + 端口上报给注册中心。 - 消费者需要时发现:按服务名查到当前可用的实例列表,再挑一个调用。
- 心跳续约:实例定期发心跳,宕机了注册中心就把它踢下线。
一句话:注册中心 = 服务的"通讯录"。服务上下线,通讯录自动增删。
2、启动 Nacos(单机)
1、下载解压
cd /opt
# 下载 Nacos(版本以 3.1.x 为准)
sudo wget https://github.com/alibaba/nacos/releases/download/3.1.1/nacos-server-3.1.1.tar.gz
sudo tar -zxvf nacos-server-3.1.1.tar.gz
sudo mv nacos /usr/local/nacos
2、必做:配置鉴权三件套(Nacos 3.x 强制)
Nacos 3.x 起,鉴权相关的三项配置不允许留空,缺一个就启动失败,而且是逐项报错——补完一个会接着报下一个:
# 第一次启动报:
The initial key used to generate JWT tokens (the original string must be over 32 characters and Base64 encoded).
`nacos.core.auth.plugin.nacos.token.secret.key` is missing, please set with Base64 string:
# 补上密钥再启动,又报:
`nacos.core.auth.server.identity.key` is missing, please set:
所以一次性把三项都配好:
| 配置项 | 要求 | 用途 |
|---|---|---|
nacos.core.auth.plugin.nacos.token.secret.key | Base64 字符串,解码后原始长度 ≥ 32 字符 | 签发 JWT 的密钥 |
nacos.core.auth.server.identity.key | 非空、自定义 | 服务端之间调用的身份标识 |
nacos.core.auth.server.identity.value | 非空、自定义 | 与上面配对使用 |
cd /usr/local/nacos/conf
# 生成三项随机值(token 需 Base64;identity 用十六进制即可,保证够长)
KEY=$(openssl rand -base64 48 | tr -d '\n')
IDK=$(openssl rand -hex 16)
IDV=$(openssl rand -hex 16)
# 先清掉可能存在的旧配置行,再一次性追加
sudo sed -i '/^nacos.core.auth.plugin.nacos.token.secret.key=/d' application.properties
sudo sed -i '/^nacos.core.auth.server.identity./d' application.properties
{
echo "nacos.core.auth.plugin.nacos.token.secret.key=$KEY"
echo "nacos.core.auth.server.identity.key=$IDK"
echo "nacos.core.auth.server.identity.value=$IDV"
} | sudo tee -a application.properties
# 确认:三行都要独立成行,且行首必须是 nacos(不能是 #)
grep -n "^nacos.core.auth" application.properties
三个坑(都有人踩过):
- 别抄网上的示例密钥。网上流传的那些"Nacos 示例密钥"是公开值,复制过来等于没设。
- 追加前先确认文件末尾有换行符。若最后一行没有换行,
tee -a会把新配置粘到上一行末尾;一旦上一行以#开头(如#nacos.k8s.sync.kubeConfig=...),整行就变成注释——配置看着写进去了,实际完全不生效。上面用grep -n "^nacos.core.auth"(^锚定行首)就是为了立刻发现这种情况。- 将来搭集群时,各节点的这三项必须完全一致,否则会报
403 invalid token。
3、单机启动
cd /usr/local/nacos
# 目录属主是 root,用 sudo 启动,否则日志写不进去
# ⚠️ 必须加 -m standalone!不加默认是集群模式,会去找外部 MySQL
sudo sh bin/startup.sh -m standalone
# 若报 "[[" 符号找不到,改用 bash 执行:sudo bash bin/startup.sh -m standalone
# 查看日志确认启动成功
tail -f /usr/local/nacos/logs/start.out
为什么必须加
-m standalone:启动参数nacos.standalone的默认值是false,即 Nacos 不加参数时默认按集群模式启动。集群模式需要外置 MySQL(读db.num、db.url.0等配置),单机学习环境没有这些配置,日志里就会抛:Caused by: java.lang.IllegalArgumentException: db.num is null加上
-m standalone后走内置 Derby 数据库,不需要任何数据库配置。
日志里出现 Nacos started successfully in stand alone mode 即为成功。
启动后:
- 控制台地址:http://localhost:8080/ (⚠️ Nacos 3.x 起控制台端口为 8080,且不再有
/nacos前缀;8848/nacos是 2.x 时代的地址) - 默认账号:
nacos/nacos
端口说明:
8848= HTTP API 端口;9848= gRPC 端口(Nacos 2.x 起新增,防火墙需放行);8080= 控制台端口(3.x 起独立)。与课程其它端口不冲突:网关用 80、user-service 8081、product-service 8082、order-service 8083、inventory-service 8084,Nacos 控制台独占 8080。
生产环境 Nacos 需要集群部署。
3、服务提供者接入 Nacos
1、加依赖
<!-- user-service/pom.xml 增加 -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
2、配置 Nacos 地址
spring:
application:
name: user-service # 服务名:注册/发现都靠它
cloud:
nacos:
server-addr: 192.168.100.100:8848 # 注册中心地址(客户端通信端口,不是控制台的 8080)
discovery:
ip: 127.0.0.1 # 注册的 IP(生产用真实网卡 IP),就是给消费端访问的地址
⚠️ 端口别写错:是
8848,不是8080
server-addr填的是 Nacos 的客户端通信端口8848,写成控制台端口8080会导致服务启动直接失败:Caused by: com.alibaba.nacos.api.exception.NacosException: Client not connected, current status:STARTING at com.alibaba.nacos.common.remote.client.RpcClient.request(RpcClient.java:647)原因:客户端以
server-addr的端口为主端口,并在其基础上 +1000 推导 gRPC 端口。写8848→ 连9848(正常);写8080→ 去连9080(根本没这个服务),连接建不起来(状态停在STARTING),注册随之失败。上一条报错Failed to start bean 'webServerStartStop'也是这么被连锁触发的。记忆口诀:8848 给程序用,8080 给浏览器用。
补充:Nacos 3.x 默认只开启控制台鉴权(浏览器登录
nacos/nacos),客户端鉴权nacos.core.auth.enabled默认是false,所以 Spring Boot 这边暂时不需要配username/password。
3、写一个接口并启动
@RestController
public class UserController {
@GetMapping("/user/{id}")
public String getUser(@PathVariable Long id) {
return "user-" + id + " @ user-service";
}
}
启动应用,刷新 Nacos 控制台 服务管理 → 服务列表,可以看到 user-service 已注册。
验证:
curl http://localhost:8081/user/1能返回结果;Nacos 里能看到实例(含 IP/端口/健康状态)。
操作完成后,在 Nacos 管理控制台看到如下效果说明注册成功:

4、服务消费者接入 Nacos
再建一个 order-service,加同样的 nacos-discovery 依赖与 Nacos 配置,然后按服务名发现实例、用 RestTemplate 发起调用。
// ① 先在 order-service 里准备一个 RestTemplate Bean(放配置类中)
@Configuration
public class RestTemplateConfig {
@Bean
public RestTemplate restTemplate() {
return new RestTemplate();
}
}
// ② 消费者按服务名发现实例,再用 RestTemplate 发起调用
@RestController
public class OrderController {
@Autowired
private DiscoveryClient discoveryClient; // Spring Cloud 提供
@Autowired
private RestTemplate restTemplate; // 用来发起 HTTP 调用
@GetMapping("/order/call")
public String callUser(@RequestParam Long id) {
// 1. 按服务名发现所有实例
List<ServiceInstance> list =
discoveryClient.getInstances("user-service");
// 2. 取第一个实例的地址
ServiceInstance ins = list.get(0);
String url = "http://" + ins.getHost() + ":" + ins.getPort()
+ "/user/" + id;
// 3. 用 RestTemplate 发起 HTTP 调用:
// getForObject 会自动把响应体反序列化成 String 返回
return restTemplate.getForObject(url, String.class);
}
}
生产里不用手写
RestTemplate+ 手工挑实例——第 05 讲 OpenFeign + 第 06 讲 LoadBalancer 会把这块全部自动化。这里先演示底层原理。
5、健康检查与上下线
| 概念 | 说明 |
|---|---|
| 心跳续约 | 实例每 5 秒发一次心跳,默认 15 秒内没收到判为不健康 |
| 主动下线 | 服务正常关闭(kill/停机)时,Nacos 会及时摘除实例 |
| 临时实例 | 默认类型,宕机自动摘除(微服务常用) |
| 持久实例 | 手动管理,适合特殊场景(本课程不展开) |
演示:停掉 user-service,刷新 Nacos,实例列表里 user-service 消失;再启动又出现。
6、课堂练习
- 启动 Nacos,打开控制台(
http://localhost:8080/,nacos/nacos 登录),确认能正常进入。 - 让
user-service注册成功,在控制台确认实例健康。 - 让
order-service用DiscoveryClient按服务名找到并调用 user-service 的接口。 - (挑战)把 user-service 用不同端口开两个实例(如 8081、8091),看控制台实例变两个,服务调用仍可用。
7、本讲小结
- Nacos = 服务注册中心,服务启动注册、消费者按名发现、心跳保证健康。
- 接入三步:加 discovery 依赖 → 配 server-addr → 启动注册。
spring.application.name就是服务名,注册与发现都靠它。- 手写发现+调用是"原理演示",真实项目用 Feign + LoadBalancer(后续两讲)。
8、本节验证
- 理解注册中心的作用与心跳续约机制 ✅
- 会配置鉴权三件套(token 密钥 + identity)并启动 Nacos ✅
- 知道启动必须加
-m standalone(不加默认走集群模式,会抛db.num is null)✅ - 知道
server-addr要填客户端端口8848(填成控制台端口 8080 会报Client not connected)✅ - 会打开 Nacos 3.x 控制台(8080,无
/nacos前缀)✅ - 会让服务提供者/消费者接入 Nacos(加依赖、配地址、注册)✅
- 会查看健康状态与实例上下线 ✅