Skip to content
第 223 / 250 章架构⏱ 12 分钟阅读

第 223 章:Nacos 服务发现与配置中心

学习目标

  • 部署 Nacos 服务
  • 集成服务注册与发现
  • 使用 Nacos Config 配置中心
  • 多环境配置管理

一、Nacos 简介

Nacos(Naming and Configuration Service)是阿里开源的注册中心 + 配置中心。

1.1 核心能力

能力说明
服务发现注册 + 健康检查 + DNS
配置管理集中化配置 + 动态推送
元数据管理标签 + 版本路由
命名空间多环境隔离

1.2 与其他对比

特性NacosEurekaConsulZookeeper
健康检查✅ TCP/HTTP/MySQL✅ 客户端心跳✅ 服务端✅ TCP
一致性AP/CP 可切APCPCP
配置中心
多语言
性能
推荐度⭐⭐⭐⭐⭐⚠️ 停维⭐⭐⭐⭐⭐

二、部署 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-east

3.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: true
java
@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_GROUP

5.3 DataId 规则

${spring.application.name}-${spring.profiles.active}.${file-extension}

例:
order-service.yaml
order-service-dev.yaml
order-service-prod.yaml

5.4 Nacos 创建配置

控制台 配置管理 → 配置列表 → +

字段
Data IDorder-service-prod.yaml
GroupDEFAULT_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: true

5.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: 15

7.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=SecretKey012345678901234567890123456789012345678901234567890123456789

9.2 客户端配置

yaml
spring:
  cloud:
    nacos:
      username: nacos
      password: nacos

9.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: true

10.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 隔离
健康检查心跳机制
负载均衡同集群优先 + 随机
容灾本地缓存 + 重试

动手练习

  1. 启动 Nacos 单机版,创建 dev / prod 两个 namespace
  2. 注册 2 个微服务(订单、库存)到 Nacos
  3. 在 Nacos 上创建 order-service-dev.yaml 配置
  4. 用 OpenFeign 调用库存服务,验证服务发现
  5. 改 Nacos 配置,观察 @RefreshScope Bean 自动刷新

推荐阅读


下一章:第 224 章:OpenFeign 服务调用

本站基于 VitePress 构建 · 由 Codebook 团队维护