SpringCloud Alibaba 核心组件解析:服务注册与发现(Nacos)
技术栈 :Spring Boot 3.2.0 + Spring Cloud 2023.0.0 + Spring Cloud Alibaba 2023.0.0.0-RC1 + Nacos
1.1 是什么 --- Nacos 定位与核心能力
1.1.1 一句话定义
Nacos(Dynamic Na ming and Co nfiguration S ervice)= 注册中心 + 配置中心 的二合一解决方案。
1.1.2 生活化类比:公司前台 + 公告栏
┌─────────────────────────────────┐
│ Nacos │
│ │
│ ┌─────────┐ ┌─────────────┐ │
│ │ 注册中心 │ │ 配置中心 │ │
│ │ (前台) │ │ (公告栏) │ │
│ │ │ │ │ │
│ │ 员工报到 │ │ 公司通知 │ │
│ │ 离职注销 │ │ 配置变更 │ │
│ │ 查同事 │ │ 大家看到 │ │
│ └─────────┘ └─────────────┘ │
└─────────────────────────────────┘
- 注册中心 = 前台:新员工入职登记、离职注销、查某人在哪个工位
- 配置中心 = 公告栏:公司通知张贴在公告栏,所有人实时看到更新
1.1.3 阿里内部验证
Nacos 在阿里巴巴内部经过双十一核心链路 验证,管理着超过 10 万+ 服务实例,是阿里云微服务引擎 MSE 的核心组件。
1.2 为什么 --- Nacos 相比 Eureka/Consul 的优势
1.2.1 一站式 vs 多组件
Eureka : 仅注册中心
Consul : 注册中心 + KV配置
Nacos : 注册中心 + 配置中心(功能完整,自带管理控制台)
1.2.2 AP + CP 可切换
其他注册中心:
Eureka = 纯 AP(高可用,可能拿到过期数据)
Consul = 纯 CP(强一致,选主期间不可用)
ZK = 纯 CP
Nacos:
AP 模式(默认)→ 适合互联网高并发场景
CP 模式 → 适合金融/支付强一致场景
→ 一个组件适配两种需求!
1.2.3 功能对比表
| 维度 | Nacos | Consul | Eureka |
|---|---|---|---|
| CAP 模型 | AP + CP 可切换 | CP | AP |
| 一致性协议 | Raft(CP) + Distro(AP) | Raft | --- |
| 配置中心 | ✅ 完整 | ✅ KV 存储 | ❌ |
| 动态刷新 | ✅ @RefreshScope |
✅ @RefreshScope |
❌ |
| 控制台 | ✅ 功能强大 | ✅ 较基础 | ✅ 基础 |
| 权重/元数据 | ✅ | ❌ | ✅ |
| 多数据中心 | ✅ | ✅ | ❌ |
| 运维复杂度 | 中 | 低 | 中 |
| 阿里生态整合 | ✅ 原生(Sentinel/Seata/RocketMQ) | ❌ | ❌ |
1.3 怎么做 --- Nacos 完整实战
1.3.1 启动 Nacos Server
bash
# Windows 单机模式
startup.cmd -m standalone
# Linux/Mac
sh startup.sh -m standalone
# 访问控制台:http://localhost:8848/nacos
# 默认账号/密码:nacos/nacos
1.3.2 项目模块
| 模块 | 端口 | 角色 |
|---|---|---|
cloudalibaba-provider-payment9001 |
9001 | Provider(注册到 Nacos) |
cloudalibaba-consumer-nacos-order83 |
83 | Consumer(从 Nacos 发现服务) |
1.3.3 步骤 ①:引入依赖
xml
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
<!-- 如需配置中心功能,额外引入: -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
</dependency>
1.3.4 步骤 ②:Provider 配置
yaml
server:
port: 9001
spring:
application:
name: nacos-payment-provider # 服务名(注册到 Nacos 用的名字)
cloud:
nacos:
discovery:
server-addr: localhost:8848 # Nacos Server 地址
sentinel:
transport:
dashboard: localhost:8080
port: 8719
1.3.5 步骤 ③:Provider 启动类
java
@SpringBootApplication
@EnableDiscoveryClient // ← 通用服务发现注解
public class Main9001 {
public static void main(String[] args) {
SpringApplication.run(Main9001.class, args);
}
}
1.3.6 步骤 ④:Provider Controller
java
@RestController
public class PayAlibabaController {
@Value("${server.port}")
private String serverPort;
@GetMapping(value = "/pay/nacos/{id}")
public String getPayInfo(@PathVariable("id") Integer id) {
return "nacos registry, serverPort: " + serverPort + "\t id" + id;
}
// Sentinel 保护的接口(同时用于 Feign 调用)
@GetMapping("/pay/nacos/get/{orderNo}")
@SentinelResource(value = "getPayByOrderNo",
blockHandler = "handlerBlockHandler")
public ResultData getPayByOrderNo(@PathVariable("orderNo") String orderNo) {
PayDTO payDTO = new PayDTO();
payDTO.setId(1024);
payDTO.setOrderNo(orderNo);
payDTO.setAmount(BigDecimal.valueOf(9.9));
payDTO.setPayNo("pay:" + IdUtil.fastUUID());
payDTO.setUserId(1);
return ResultData.success("查询返回值:" + payDTO);
}
// Sentinel 流控的 fallback
public ResultData handlerBlockHandler(@PathVariable("orderNo") String orderNo,
BlockException exception) {
return ResultData.fail(ReturnCodeEnum.RC500.getCode(),
"getPayByOrderNo服务不可用,触发sentinel流控配置规则");
}
}
1.3.7 步骤 ⑤:Consumer 配置
yaml
server:
port: 83
spring:
application:
name: nacos-order-consumer
cloud:
nacos:
discovery:
server-addr: localhost:8848
sentinel:
log:
dir: D:/yangnan/Documents/SpringCloud/sentinel-log
# Provider 的服务名
service-url:
nacos-user-service: http://nacos-payment-provider
# 激活 Sentinel 对 Feign 的支持
feign:
sentinel:
enabled: true
1.3.8 步骤 ⑥:Consumer RestTemplate + Feign 混合调用
java
@RestController
public class OrderNacosController {
@Resource
private RestTemplate restTemplate;
@Value("${service-url.nacos-user-service}")
private String serverURL; // http://nacos-payment-provider
// RestTemplate 方式
@GetMapping("/consumer/pay/nacos/{id}")
public String paymentInfo(@PathVariable("id") Integer id) {
return restTemplate.getForObject(serverURL + "/pay/nacos/" + id,
String.class) + "\t 我是OrderNacosController83调用者";
}
// Feign + Sentinel 方式
@Resource
private PayFeignSentinelApi payFeignSentinelApi;
@GetMapping(value = "/consumer/pay/nacos/get/{orderNo}")
public ResultData getPayByOrderNo(@PathVariable("orderNo") String orderNo) {
return payFeignSentinelApi.getPayByOrderNo(orderNo);
}
}
1.3.9 验证
- 启动 Nacos → Provider(9001) → Consumer(83)
- 打开
http://localhost:8848/nacos→ 服务列表 → 看到nacos-payment-provider和nacos-order-consumer - 访问
http://localhost:83/consumer/pay/nacos/1→ 返回 Provider 的端口号
1.4 深入原理 --- Nacos AP + CP 切换
1.4.1 架构
Nacos Server 集群
┌──────────────────────────────┐
│ Leader (Raft 选主) │ ← CP 模式(配置数据)
│ → 配置数据一致性由 Raft 保证 │
├──────────────────────────────┤
│ 全部节点 │ ← AP 模式(服务数据)
│ → 服务数据用 Distro 协议同步 │
└──────────────────────────────┘
1.4.2 持久化
Nacos 默认使用内嵌 Derby 数据库,生产环境需切换到 MySQL:
properties
# nacos/conf/application.properties
spring.datasource.platform=mysql
db.num=1
db.url.0=jdbc:mysql://localhost:3306/nacos_config?characterEncoding=utf8&connectTimeout=1000&socketTimeout=3000&autoReconnect=true
db.user=root
db.password=123456
1.5 Nacos vs Consul 配置对比
| 配置项 | Nacos | Consul |
|---|---|---|
| 注册中心注解 | @EnableDiscoveryClient |
@EnableDiscoveryClient |
| 注册地址 | spring.cloud.nacos.discovery.server-addr |
spring.cloud.consul.host + port |
| 服务名 | spring.application.name |
spring.application.name |
| 控制台 | http://localhost:8848/nacos |
http://localhost:8500 |
| 配置中心注解 | @RefreshScope(同) |
@RefreshScope(同) |
1.6 面试题
Q1:Nacos 如何实现 AP 和 CP 的切换?
答 :Nacos 对于临时实例 (ephemeral: true,默认)使用自研的 Distro 协议保证 AP;对于持久化实例 (ephemeral: false)使用 Raft 协议保证 CP。配置数据始终使用 CP 模式。通过在客户端配置 spring.cloud.nacos.discovery.ephemeral=false 切换。
Q2:Nacos 和 Eureka 的核心区别?
答:
- Nacos = 注册中心 + 配置中心,Eureka 仅是注册中心
- Nacos 支持 AP/CP 切换,Eureka 只能是 AP
- Nacos 使用 Netty 长连接 + HTTP 两种通信方式,Eureka 仅 HTTP
- Nacos 有完善的权重/元数据/分组/命名空间机制
1.7 踩坑指南
| 坑 | 现象 | 原因 | 解决 |
|---|---|---|---|
| 🔴 Nacos 连接不上 | Connection refused |
Nacos Server 未启动或端口错误 | 确认 startup.cmd -m standalone |
| 🔴 服务名不对 | UnknownHostException |
Consumer 填写的服务名与 Provider 的 spring.application.name 不一致 |
严格保持一致 |
| 🔴 Nacos 控制台看不到服务 | 注册失败 | 未引入 @EnableDiscoveryClient |
检查启动类注解 |
| 🔴 版本冲突 | 启动报错 | Spring Cloud Alibaba 版本与 Spring Boot/Cloud 版本不兼容 | 查阅版本对应表 |
1.8 章节总结
| 要点 | 说明 |
|---|---|
| Nacos = 注册中心 + 配置中心 | 一个组件替代 Eureka + Config |
| AP + CP 可切换 | 默认 AP(Distro),配置 ephemeral=false 切换 CP(Raft) |
| 阿里验证 | 双十一核心链路,10 万+ 实例 |
| 关键注解 | @EnableDiscoveryClient(通用)+ @RefreshScope |
| 关键配置 | spring.cloud.nacos.discovery.server-addr: localhost:8848 |
| 生产建议 | 持久化切换到 MySQL,集群部署至少 3 节点 |