第 223 章:Nacos 服务发现与配置中心
学习目标
- 部署 Nacos 服务
- 集成服务注册与发现
- 使用 Nacos Config 配置中心
- 多环境配置管理
一、Nacos 简介
Nacos(Naming and Configuration Service)是阿里开源的注册中心 + 配置中心。
1.1 核心能力
| 能力 | 说明 |
|---|---|
| 服务发现 | 注册 + 健康检查 + DNS |
| 配置管理 | 集中化配置 + 动态推送 |
| 元数据管理 | 标签 + 版本路由 |
| 命名空间 | 多环境隔离 |
1.2 与其他对比
| 特性 | Nacos | Eureka | Consul | Zookeeper |
|---|---|---|---|---|
| 健康检查 | ✅ TCP/HTTP/MySQL | ✅ 客户端心跳 | ✅ 服务端 | ✅ TCP |
| 一致性 | AP/CP 可切 | AP | CP | CP |
| 配置中心 | ✅ | ❌ | ✅ | ❌ |
| 多语言 | ✅ | ❌ | ✅ | ✅ |
| 性能 | 高 | 高 | 高 | 中 |
| 推荐度 | ⭐⭐⭐⭐⭐ | ⚠️ 停维 | ⭐⭐⭐ | ⭐⭐ |
二、部署 Nacos
2.1 单机模式(开发)
bash
docker run -d --name nacos -p 8848:8848 -p 9848:9848 \
-e MODE=standalone \
-e JVM_XMS=512m -e JVM_XMX=512m \
nacos/nacos-server:v2.3.0访问: http://localhost:8848/nacos 默认账号: nacos / nacos
2.2 集群模式(生产)
yaml
# docker-compose.yml
version: '3.8'
services:
nacos1:
hostname: nacos1
container_name: nacos1
image: nacos/nacos-server:v2.3.0
volumes:
- ./cluster.conf:/home/nacos/conf/cluster.conf
ports: ["8848:8848","9848:9848"]
environment:
- SPRING_DATASOURCE_PLATFORM=mysql
- MYSQL_SERVICE_HOST=mysql
- MYSQL_SERVICE_DB_NAME=nacos
- MYSQL_SERVICE_USER=nacos
- MYSQL_SERVICE_PASSWORD=nacos
- NACOS_SERVERS=nacos1:8848 nacos2:8848 nacos3:8848依赖 MySQL 持久化,推荐 3 节点 HA。
2.3 K8s 部署
bash
helm repo add nacos https://nacos-group.github.io/nacos-helm-chart
helm install nacos nacos/nacos --namespace nacos --create-namespace三、服务注册与发现
3.1 服务端引入依赖
xml
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>3.2 配置
yaml
spring:
application:
name: order-service
cloud:
nacos:
discovery:
server-addr: 127.0.0.1:8848
namespace: dev
group: DEFAULT_GROUP
username: nacos
password: nacos
# 注册 IP(多网卡时指定)
ip: 192.168.1.10
# 注册端口(默认取 server.port)
port: 8081
# 元数据
metadata:
version: v1
region: cn-east3.3 启动类
java
@SpringBootApplication
@EnableDiscoveryClient
public class OrderServiceApplication {
public static void main(String[] args) {
SpringApplication.run(OrderServiceApplication.class, args);
}
}启动后,Nacos 控制台 服务列表 出现 order-service。
3.4 服务发现 API
java
@RestController
public class DiscoveryController {
@Autowired
private DiscoveryClient discoveryClient;
@GetMapping("/services")
public List<String> list() {
return discoveryClient.getServices();
}
@GetMapping("/instances/{name}")
public List<ServiceInstance> instances(@PathVariable String name) {
return discoveryClient.getInstances(name);
}
}3.5 Nacos Open API
bash
# 注册
curl -X POST 'http://nacos:8848/nacos/v1/ns/instance?serviceName=order-service&ip=192.168.1.10&port=8081'
# 查询实例
curl 'http://nacos:8848/nacos/v1/ns/instance/list?serviceName=order-service'
# 注销
curl -X DELETE 'http://nacos:8848/nacos/v1/ns/instance?serviceName=order-service&ip=192.168.1.10&port=8081'四、客户端负载均衡
4.1 OpenFeign 集成
java
// Feign 自动从 Nacos 拉取实例 + 负载均衡
@FeignClient("inventory-service")
public interface InventoryClient {
@GetMapping("/api/inventory/{skuId}")
InventoryDTO getStock(@PathVariable String skuId);
}4.2 RestTemplate + LoadBalancer
java
@Configuration
public class RestTemplateConfig {
@Bean
@LoadBalanced
public RestTemplate restTemplate() {
return new RestTemplate();
}
}
@Service
public class OrderService {
@Autowired
private RestTemplate restTemplate;
public InventoryDTO queryStock(String skuId) {
// 自动负载均衡
return restTemplate.getForObject(
"http://inventory-service/api/inventory/" + skuId,
InventoryDTO.class
);
}
}4.3 Spring Cloud LoadBalancer 规则
yaml
spring:
cloud:
loadbalancer:
ribbon:
enabled: false # Spring Cloud LoadBalancer 替代 Ribbon
nacos:
enabled: truejava
@Bean
public ReactorLoadBalancer<ServiceInstance> loadBalancer(
Environment env,
LoadBalancerClientFactory factory
) {
// 自定义:同集群优先 + 随机
return new NacosLoadBalancer(
factory.getLazyProvider(env.getProperty("spring.cloud.nacos.discovery.server-addr"),
ServiceInstanceListSupplier.class
),
new NacosDiscoveryProperties()
);
}五、配置中心
5.1 引入依赖
xml
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
</dependency>5.2 bootstrap.yml
yaml
spring:
application:
name: order-service
cloud:
nacos:
config:
server-addr: 127.0.0.1:8848
file-extension: yaml
namespace: prod
group: DEFAULT_GROUP
username: nacos
password: nacos
# 配置刷新
refresh-enabled: true
# 共享配置
shared-configs:
- data-id: common.yaml
group: DEFAULT_GROUP
refresh: true
- data-id: redis.yaml
group: DEFAULT_GROUP5.3 DataId 规则
${spring.application.name}-${spring.profiles.active}.${file-extension}
例:
order-service.yaml
order-service-dev.yaml
order-service-prod.yaml5.4 Nacos 创建配置
控制台 配置管理 → 配置列表 → +
| 字段 | 值 |
|---|---|
| Data ID | order-service-prod.yaml |
| Group | DEFAULT_GROUP |
| 配置格式 | YAML |
| 配置内容 | 见下 |
yaml
server:
port: 8081
spring:
datasource:
url: jdbc:mysql://prod-mysql:3306/order
password: ${DB_PASS}
order:
timeout: 5000
maxRetry: 3
feature:
enabled: true5.5 动态刷新
java
@RefreshScope
@RestController
public class OrderConfigController {
@Value("${order.timeout}")
private int timeout;
@Value("${order.feature.enabled}")
private boolean featureEnabled;
@GetMapping("/config")
public Map<String, Object> config() {
return Map.of(
"timeout", timeout,
"featureEnabled", featureEnabled
);
}
}修改 Nacos 配置后,无需重启应用,30 秒内自动生效。
5.6 监听配置变化
java
@Configuration
public class ConfigListener implements ApplicationRunner {
@Autowired
private NacosConfigManager nacosConfigManager;
@Override
public void run(ApplicationArguments args) {
NacosConfigProperties props = nacosConfigManager.getNacosConfigProperties();
NacosFactory.createConfigService(props.serverAddr())
.addListener("order-service.yaml", "DEFAULT_GROUP", new Listener() {
@Override
public void receiveConfigInfo(String configInfo) {
log.info("配置变化: {}", configInfo);
// 重启某些 bean
}
});
}
}六、命名空间与分组
6.1 多环境隔离
每个环境独立命名空间,数据完全隔离。
6.2 业务分组
同一 namespace 内用 group 进一步隔离。
6.3 实战配置
yaml
# order-service 启动配置
spring:
cloud:
nacos:
discovery:
namespace: prod # 注册:生产命名空间
config:
namespace: prod # 配置:生产命名空间
group: TRADE_GROUP # 业务分组七、健康检查
7.1 检查类型
| 类型 | 说明 |
|---|---|
| 临时实例 | 客户端心跳(默认),下线自动删除 |
| 永久实例 | 服务端主动探活,需主动注销 |
7.2 配置
yaml
spring:
cloud:
nacos:
discovery:
# 临时实例(默认)
ephemeral: true
# 心跳间隔
heart-beat-interval: 5
# 心跳超时
heart-beat-timeout: 157.3 健康指示器
yaml
management:
endpoint:
health:
show-details: always
health:
nacos:
enabled: true/actuator/health 会包含 Nacos 健康状态。
八、集群路由与就近访问
8.1 同集群优先
yaml
# 在 Nacos 注册时加 cluster-name
spring:
cloud:
nacos:
discovery:
cluster-name: SH # 上海集群
# 客户端其他实例也标 SH
# OpenFeign 默认优先同集群调用8.2 自定义 LoadBalancer
java
@Bean
public ReactorLoadBalancer<ServiceInstance> sameClusterFirstLB(
ServiceInstanceListSupplier supplier,
NacosDiscoveryProperties props
) {
return new SameClusterFirstNacosLoadBalancer(supplier, props);
}java
public class SameClusterFirstNacosLoadBalancer
implements ReactorLoadBalancer<ServiceInstance> {
private final ObjectProvider<ServiceInstanceListSupplier> supplier;
private final NacosDiscoveryProperties props;
@Override
public Mono<Response<ServiceInstance>> choose(Request request) {
return supplier.getObject().getInstances(request)
.collectList()
.map(instances -> {
String localCluster = props.getClusterName();
// 1. 同集群
List<ServiceInstance> same = instances.stream()
.filter(i -> localCluster.equals(
((NacosServiceInstance) i).getInstance().getClusterName()))
.collect(Collectors.toList());
// 2. 同集群空 → 全部
List<ServiceInstance> target = same.isEmpty() ? instances : same;
// 3. 随机选
int idx = ThreadLocalRandom.current().nextInt(target.size());
return new Response<>(target.get(idx));
});
}
}九、安全
9.1 开启鉴权
properties
# nacos/conf/application.properties
nacos.core.auth.enabled=true
nacos.core.auth.server.identity.key=mySecretKey
nacos.core.auth.server.identity.value=mySecretValue
nacos.core.auth.plugin.nacos.token.secret.key=SecretKey0123456789012345678901234567890123456789012345678901234567899.2 客户端配置
yaml
spring:
cloud:
nacos:
username: nacos
password: nacos9.3 命名空间 RBAC
Nacos 2.2+ 支持基于命名空间和组的细粒度权限管理(企业版需配置)。
十、容灾
10.1 本地缓存
Nacos 客户端内嵌缓存文件,服务端不可用时仍可读配置。
yaml
spring:
cloud:
nacos:
config:
# 启用本地缓存
watch:
enabled: true
# 拉取超时
timeout: 5000${user.home}/nacos/config/ 路径下有 snapshot。
10.2 服务下线自保护
yaml
spring:
cloud:
nacos:
discovery:
# 心跳丢失后多久剔除(15-30s)
heart-beat-timeout: 15000
# 服务元数据
metadata:
preserve: true10.3 客户端重试
yaml
spring:
cloud:
nacos:
config:
# 重试
max-retries: 3
# 重试间隔
config-retry-time: 2000十一、与 OpenFeign / Gateway 整合
11.1 自动注册
三个组件都用同一种注解:
java
@SpringBootApplication
@EnableDiscoveryClient // 或 @EnableFeignClients
public class OrderService { ... }11.2 OpenFeign + Nacos
java
@FeignClient(name = "inventory-service")
public interface InventoryClient { ... }OpenFeign 自动从 Nacos 获取 inventory-service 的所有实例,客户端负载均衡。
11.3 Gateway + Nacos
yaml
spring:
cloud:
gateway:
discovery:
locator:
enabled: true # 根据 serviceId 自动生成路由http://gateway:9000/inventory-service/api/inventory/SKU-001
十二、监控
12.1 Prometheus 暴露
yaml
management:
endpoints:
web:
exposure:
include: "*"12.2 关键指标
nacos_client_request_duration_seconds # 请求耗时
nacos_client_response_size_bytes # 响应大小
nacos_client_active # 活跃请求
nacos_config_subscriptions_total # 配置订阅数12.3 服务治理 Dashboard
通过 Nacos 控制台查看:
- 注册实例数
- 健康状态
- 配置变更历史
十三、本章小结
| 主题 | 要点 |
|---|---|
| 部署 | 单机 / 集群 / K8s |
| 注册 | spring-cloud-starter-alibaba-nacos-discovery |
| 配置 | spring-cloud-starter-alibaba-nacos-config |
| 动态刷新 | @RefreshScope |
| 多环境 | namespace 隔离 |
| 健康检查 | 心跳机制 |
| 负载均衡 | 同集群优先 + 随机 |
| 容灾 | 本地缓存 + 重试 |
动手练习
- 启动 Nacos 单机版,创建 dev / prod 两个 namespace
- 注册 2 个微服务(订单、库存)到 Nacos
- 在 Nacos 上创建 order-service-dev.yaml 配置
- 用 OpenFeign 调用库存服务,验证服务发现
- 改 Nacos 配置,观察
@RefreshScopeBean 自动刷新