本篇延续前两篇确定的 Spring Cloud Alibaba 技术分层,重点展开 Nacos 的注册发现、配置治理、环境隔离和生产高可用能力。


发布信息

文章标题:

微服务架构高级应用(三):Nacos 注册中心与配置中心企业级设计

推荐副标题:

从“服务能注册、配置能读取”走向环境隔离、灰度治理、审计回滚与高可用

文章摘要:

在很多 Spring Cloud Alibaba 项目中,Nacos 只是被用来注册服务和保存 YAML 配置,但这距离企业级应用仍然有很大差距。结合我长期参与 Java 后端、微服务、电商、物流、政企和物联网项目的实践,本文从架构设计和生产交付角度,系统讲清 Nacos 的服务注册、健康检查、Namespace、Group、Cluster、实例元数据、配置拆分、动态刷新、敏感信息保护、灰度发布、变更审计、集群部署和验收标准,给出一套可以直接应用到企业项目中的 Nacos 设计方案。

推荐标签:

Nacos
Spring Cloud Alibaba
Spring Cloud
微服务
Java
配置中心
注册中心
服务治理
系统架构
高可用

微服务架构高级应用(三):Nacos 注册中心与配置中心企业级设计

对我来说,Nacos 接入成功的标准从来不是“服务出现在控制台里”或者“配置能读取出来”。

真正的企业级标准是:环境不会串、配置可治理、变更可追踪、异常可回滚、节点故障后服务仍然能够运行。

文章目录


前言

我长期做 Java 后端、微服务架构和项目交付,在电商管理平台、智慧物流、政企系统、物联网接入平台等项目中,Nacos 几乎已经成为 Spring Cloud Alibaba 技术体系里的基础组件。

很多项目对 Nacos 的接入方式都比较相似:

  1. 部署一个 Nacos 服务;
  2. 引入 Nacos Discovery;
  3. 在配置文件中写入 server-addr
  4. 启动服务;
  5. 在控制台看到服务实例;
  6. 再把数据库、Redis 和 RocketMQ 配置放进 Nacos。

做到这里,功能层面似乎已经完成了。

但进入测试、预发布和生产环境以后,问题很快就会暴露出来:

  • 开发服务误注册到测试环境;
  • 测试服务调用了生产服务;
  • 所有配置都堆在一个 YAML 文件中;
  • 修改公共 Redis 配置导致多个服务同时异常;
  • 配置动态刷新后,线程池参数失控;
  • 数据库密码、Redis 密码直接明文保存;
  • Nacos 单节点故障后,整个微服务体系失去治理入口;
  • 配置变更后没有审计记录;
  • 错误配置发布后不知道如何快速回滚;
  • 灰度实例与正式实例无法区分;
  • 服务名称、Group、Cluster 和 Namespace 随意使用。

因此,Nacos 企业级设计不能只回答“怎么接入”,还必须回答:

服务如何隔离
配置如何拆分
权限如何控制
变更如何审计
灰度如何发布
故障如何恢复
生产如何验收

一、我如何理解 Nacos 的定位

在企业微服务体系中,我通常把 Nacos 定位为两个基础能力中心:

服务注册与发现中心
+
配置治理中心

它解决的是服务与配置的治理问题,而不是所有分布式问题。

Nacos 负责什么

Nacos 适合负责:

  • 服务实例注册;
  • 服务实例发现;
  • 服务健康检查;
  • 实例上下线通知;
  • 服务分组;
  • 集群和机房标识;
  • 服务实例元数据;
  • 应用配置集中管理;
  • 配置动态推送;
  • 配置环境隔离;
  • 配置版本记录;
  • 配置回滚;
  • 配置权限管理。

Nacos 不负责什么

Nacos 不负责:

  • 业务权限判断;
  • 用户会话管理;
  • 订单状态保存;
  • 商品库存管理;
  • 跨服务数据一致性;
  • 消息可靠投递;
  • 接口消费幂等;
  • 分布式事务补偿;
  • 业务规则高频读写;
  • 海量业务数据存储。

我在项目设计中一直强调:

Nacos 是治理基础设施,不是业务数据库,也不是万能配置仓库。

如果一个业务规则存在高频写入、复杂查询、业务审批、历史审计和事务要求,就应该由数据库和专门的业务管理模块承担,而不是直接塞进 Nacos。


二、Nacos 在微服务架构中的位置

在完整的 Spring Cloud Alibaba 微服务体系中,Nacos 通常位于服务治理层。

┌─────────────────────────────────────────────┐
│                 客户端接入层                 │
│ Web / App / 小程序 / 第三方系统 / IoT 设备   │
└─────────────────────┬───────────────────────┘
                      │
┌─────────────────────▼───────────────────────┐
│                 统一网关层                   │
│ Spring Cloud Gateway                        │
└─────────────────────┬───────────────────────┘
                      │
┌─────────────────────▼───────────────────────┐
│                 服务治理层                   │
│ Nacos / OpenFeign / LoadBalancer / Sentinel │
└─────────────────────┬───────────────────────┘
                      │
┌─────────────────────▼───────────────────────┐
│                 业务服务层                   │
│ 用户 / 商品 / 库存 / 订单 / 支付 / 消息      │
└─────────────────────────────────────────────┘

Nacos 向上支撑 Gateway 和 OpenFeign,向下管理业务服务实例与应用配置。

典型调用过程如下:

订单服务启动
   ↓
向 Nacos 注册实例
   ↓
Nacos 保存实例信息
   ↓
网关和其他服务订阅实例列表
   ↓
服务列表发生变化
   ↓
Nacos 向订阅方推送变更
   ↓
LoadBalancer 选择可用实例

因此,Nacos 的稳定性会直接影响:

  • 新实例能否被发现;
  • 下线实例能否及时移除;
  • 服务调用能否找到正确目标;
  • 动态配置能否正常下发;
  • 灰度和环境规则能否正确执行。

三、服务注册与发现的运行机制

1. 服务实例注册

一个 Spring Boot 服务启动后,会将自身信息注册到 Nacos。

注册信息通常包括:

服务名称
IP 地址
服务端口
Namespace
Group
Cluster
实例权重
健康状态
是否启用
实例元数据

示例配置:

spring:
  application:
    name: order-service

  cloud:
    nacos:
      discovery:
        server-addr: ${NACOS_SERVER_ADDR:127.0.0.1:8848}
        namespace: ${NACOS_NAMESPACE:local}
        group: ${NACOS_GROUP:TRADE_GROUP}
        cluster-name: ${NACOS_CLUSTER:LOCAL}
        metadata:
          version: v1
          region: local
          lane: stable

这里我没有把所有值写死,而是优先使用环境变量。

这样做的好处是:

  • 本地、测试和生产可以使用相同制品;
  • 不需要为了不同环境重新编译;
  • Docker 和 Kubernetes 部署更容易;
  • 敏感配置不必直接写入代码仓库。

2. 服务订阅

消费者不会每次调用都去 Nacos 查询服务列表。

正常情况下,客户端会维护本地服务实例列表,并订阅 Nacos 中的实例变化。

当实例发生以下变化时:

  • 新实例注册;
  • 实例主动下线;
  • 实例健康状态变化;
  • 实例权重变化;
  • 实例元数据变化;

Nacos 会将最新信息通知给客户端。

客户端本地列表更新后,Spring Cloud LoadBalancer 再从可用实例中选择目标实例。

因此,服务发现不是简单的“查一次注册表”,而是:

注册
+
订阅
+
本地缓存
+
变更推送
+
负载均衡

3. 健康检查

服务实例注册成功,不代表它始终健康。

Nacos 需要持续判断实例是否可用。

在架构设计上,我通常重点关注:

  • 服务是否正常启动;
  • 服务端口是否可访问;
  • 应用是否能够处理请求;
  • 数据库、Redis 等依赖是否异常;
  • 实例是否主动下线;
  • 网络是否发生分区;
  • 客户端与 Nacos 是否保持通信。

需要注意:

服务进程存在,不等于业务健康。

例如某个订单服务的 JVM 仍然存活,但数据库连接池已经耗尽,这个实例虽然没有退出,却已经无法正常提供服务。

因此,企业项目中还需要结合:

Spring Boot Actuator
Kubernetes Readiness
Kubernetes Liveness
Prometheus
SkyWalking
业务探针

共同判断服务是否真正可用。


四、临时实例与持久实例如何选择

Nacos 中的实例可以根据服务类型和生命周期采用不同管理方式。

在微服务业务系统中,大部分普通应用实例都属于动态运行实例,例如:

  • Gateway;
  • 用户服务;
  • 商品服务;
  • 订单服务;
  • 库存服务;
  • 消息服务。

这些服务可能因为以下原因上下线:

  • 应用发布;
  • 容器重启;
  • Kubernetes 扩缩容;
  • 服务器故障;
  • 灰度实例销毁。

对于此类实例,核心要求是:

实例失联后,应当能够被及时识别和移除,避免请求继续路由到故障节点。

而对于部分固定基础节点、特殊设备节点或需要服务端主动探测的场景,可以根据实际模型选择不同实例管理方式。

我的原则不是机械地选择某一种实例类型,而是先回答三个问题:

  1. 实例是否会频繁扩缩容?
  2. 实例失联后是否应立即摘除?
  3. 健康状态由客户端维护还是由服务端主动探测?

业务微服务通常强调动态生命周期和快速上下线;固定基础设施则可能更强调服务端探测和持久管理。


五、Namespace、Group、Service、Cluster 如何规划

Nacos 的企业级治理,最容易出问题的地方,就是几个核心概念没有统一规划。

我通常按以下方式理解:

概念 主要用途
Namespace 环境或大型隔离边界
Group 系统、业务域或配置类别
Service 具体微服务名称
Cluster 机房、地域或部署集群
Metadata 版本、泳道、区域和实例特征

六、Namespace:优先用于环境隔离

在我的项目设计中,Namespace 首先用于隔离不同环境。

推荐规划:

local
dev
test
staging
prod

对应关系:

Namespace 用途
local 开发人员本地环境
dev 集成开发环境
test 测试环境
staging 预发布环境
prod 生产环境

这样可以避免最危险的环境串联问题。

例如:

本地订单服务
    × 不应发现
生产库存服务
测试网关
    × 不应路由
生产用户服务
开发环境
    × 不应读取
生产数据库配置

不建议的做法

不建议所有环境共用一个 Namespace,再通过 Group 区分:

Namespace:public

Group:
DEV_GROUP
TEST_GROUP
PROD_GROUP

这种设计虽然看起来简单,但隔离强度不足。

一旦 Group 配置错误,就可能发生跨环境调用或读取错误配置。

我的建议是:

环境隔离优先使用 Namespace,Group 用于同一环境内部的业务分类。


七、Group:用于业务域和配置类别

在同一个 Namespace 内,可以通过 Group 区分业务域。

例如:

SYSTEM_GROUP
USER_GROUP
TRADE_GROUP
PRODUCT_GROUP
MARKETING_GROUP
INFRA_GROUP
MONITOR_GROUP

示例:

服务 Group
gateway-service SYSTEM_GROUP
auth-service SYSTEM_GROUP
user-service USER_GROUP
product-service PRODUCT_GROUP
stock-service PRODUCT_GROUP
order-service TRADE_GROUP
payment-service TRADE_GROUP
message-service INFRA_GROUP

Group 不宜设计得过度复杂。

如果每个服务一个 Group,就失去了分类意义;如果所有服务都放入 DEFAULT_GROUP,又失去了治理价值。


八、Service:统一服务命名规范

服务名称直接影响:

  • Nacos 服务注册;
  • OpenFeign 调用;
  • Gateway 动态路由;
  • 日志检索;
  • Prometheus 指标;
  • SkyWalking 拓扑;
  • Kubernetes Service;
  • CI/CD 发布。

因此必须统一命名。

推荐格式:

业务域-能力-service

例如:

system-gateway-service
system-auth-service
user-account-service
product-catalog-service
product-stock-service
trade-order-service
trade-payment-service
infra-message-service
infra-file-service

对于规模没有那么大的项目,也可以使用更简洁的形式:

gateway-service
auth-service
user-service
product-service
stock-service
order-service
payment-service
message-service

关键不是名称长短,而是:

命名统一
含义清晰
不可重复
长期稳定

服务名称一旦被多个系统依赖,就不应频繁修改。


九、Cluster:用于地域和机房治理

Cluster 可以用于标识:

  • 地域;
  • 机房;
  • 可用区;
  • 物理集群;
  • 网络区域。

例如:

BEIJING-A
BEIJING-B
SHANGHAI-A
GUIZHOU-A

或者:

US-EAST-1A
US-EAST-1B
US-WEST-1A

当系统跨机房部署时,可以优先调用同机房实例,减少:

  • 网络延迟;
  • 跨区域流量费用;
  • 跨机房故障影响;
  • 不必要的远程调用。

典型策略:

同 Cluster 优先
    ↓
同 Region 备选
    ↓
跨 Region 兜底

对于单机房或中小型项目,不需要为了“架构看起来高级”而强行设计大量 Cluster。

Cluster 应服务于真实的部署拓扑。


十、Metadata:灰度、版本和泳道治理的基础

实例元数据是很多项目容易忽略,但后期非常有价值的一部分。

示例:

spring:
  cloud:
    nacos:
      discovery:
        metadata:
          version: v2
          lane: gray
          region: guizhou
          zone: zone-a
          tenant: public

常见元数据包括:

字段 用途
version 服务版本
lane 流量泳道
region 部署地域
zone 可用区
env 环境标识
tenant 租户范围
protocol 调用协议
release 发布批次

通过元数据,可以实现:

  • 指定用户访问灰度版本;
  • 指定测试账号进入测试泳道;
  • 同版本服务优先调用;
  • 同区域实例优先;
  • 生产流量与验证流量隔离。

例如:

请求头:X-Lane=gray
        ↓
Gateway 识别灰度流量
        ↓
选择 metadata.lane=gray 的实例
        ↓
灰度订单服务
        ↓
继续调用同泳道库存服务

这比只在网关层切换一个服务实例更完整,因为真正的灰度链路需要保证后续服务调用也进入同一泳道。


十一、配置中心不是“把 application.yml 搬到控制台”

很多项目对配置中心的理解是:

原来配置写在项目里,现在复制到 Nacos 里。

这种做法只是改变了配置存放位置,没有形成配置治理。

企业级配置中心至少要解决:

配置分类
环境隔离
应用隔离
共享配置
敏感信息保护
动态刷新
版本管理
权限控制
变更审计
灰度验证
快速回滚

十二、配置如何拆分

我不建议一个服务只有一个几百行甚至上千行的配置文件。

例如:

order-service-prod.yaml

里面同时包含:

  • 数据库;
  • Redis;
  • RocketMQ;
  • 日志;
  • 安全;
  • 文件服务;
  • Feign;
  • Sentinel;
  • 业务开关;
  • 第三方平台。

这种方式的问题是:

  • 修改范围难控制;
  • 公共配置大量复制;
  • 不同负责人相互影响;
  • 回滚粒度过大;
  • 很难识别敏感配置;
  • 配置审计不清晰。

我通常将配置分为三类。

1. 应用独立配置

只属于当前服务:

order-service.yaml

内容包括:

  • 服务端口;
  • 订单业务参数;
  • 订单状态配置;
  • 当前服务专属线程池;
  • 当前服务专属调用参数。

2. 公共技术配置

多个服务共享:

common-redis.yaml
common-rocketmq.yaml
common-observability.yaml
common-security.yaml
common-web.yaml

3. 环境和敏感配置

与具体环境相关:

common-datasource-prod.yaml
common-secret-prod.yaml
third-party-payment-prod.yaml

但是敏感数据不应因为名字叫 secret,就直接明文放入 Nacos。

后文会进一步说明敏感配置处理方式。


十三、Data ID 命名规范

Data ID 必须统一,否则项目服务数量增加后,控制台会非常混乱。

推荐格式:

${application-name}-${profile}.${file-extension}

例如:

order-service-local.yaml
order-service-dev.yaml
order-service-test.yaml
order-service-staging.yaml
order-service-prod.yaml

公共配置可以使用:

common-web.yaml
common-redis.yaml
common-rocketmq.yaml
common-security.yaml
common-monitor.yaml

也可以按照业务域划分:

trade-common.yaml
product-common.yaml
user-common.yaml

Data ID 的命名必须体现:

属于哪个应用
属于哪个环境
属于哪类配置
采用什么格式

十四、当前项目基线的 Nacos 接入方式

结合当前项目常用基线,可以采用:

JDK 11
Spring Boot 2.7.18
Spring Cloud 2021.0.9
Spring Cloud Alibaba 2021.0.6.1
Nacos Server 2.3.0

这里强调的是项目固定基线,而不是追求单个组件的最新版本。

1. 引入依赖

<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>

依赖版本由父工程 BOM 统一管理,子模块不单独声明版本。


2. 推荐基础配置

spring:
  application:
    name: order-service

  profiles:
    active: ${SPRING_PROFILES_ACTIVE:local}

  cloud:
    nacos:
      username: ${NACOS_USERNAME:nacos}
      password: ${NACOS_PASSWORD:nacos}

      discovery:
        server-addr: ${NACOS_SERVER_ADDR:127.0.0.1:8848}
        namespace: ${NACOS_NAMESPACE:local}
        group: ${NACOS_DISCOVERY_GROUP:TRADE_GROUP}
        cluster-name: ${NACOS_CLUSTER:LOCAL}
        metadata:
          version: ${APP_VERSION:v1}
          lane: ${APP_LANE:stable}
          region: ${APP_REGION:local}

      config:
        server-addr: ${NACOS_SERVER_ADDR:127.0.0.1:8848}
        namespace: ${NACOS_NAMESPACE:local}
        group: ${NACOS_CONFIG_GROUP:TRADE_GROUP}
        file-extension: yaml
        refresh-enabled: true

在新的配置加载机制下,建议团队统一选择一种方式。

例如统一使用 Config Import:

spring:
  config:
    import:
      - optional:nacos:common-web.yaml?group=INFRA_GROUP&refreshEnabled=true
      - optional:nacos:common-redis.yaml?group=INFRA_GROUP&refreshEnabled=true
      - optional:nacos:order-service-${spring.profiles.active}.yaml?group=TRADE_GROUP&refreshEnabled=true

旧项目如果使用 bootstrap.ymlspring-cloud-starter-bootstrap,也可以继续保持稳定运行。

但我不建议:

一部分配置使用 bootstrap
另一部分使用 Config Import
开发人员又在 application.yml 中重复定义

配置加载方式一旦混用,很容易出现:

  • 优先级不清楚;
  • 配置没有生效;
  • 本地值覆盖远程值;
  • 环境变量覆盖关系不明确;
  • 排查时不知道真实配置来源。

十五、共享配置必须控制依赖方向

共享配置可以减少重复,但不能无限共享。

例如:

common-redis.yaml

可以被多个服务使用。

但是:

trade-order-business.yaml

不应被用户服务、文件服务等无关服务加载。

我的原则是:

基础技术配置可以共享
业务配置按领域隔离
服务专属配置不得反向共享

否则,一个服务修改业务参数,可能导致大量无关服务刷新配置。


十六、动态刷新不是所有配置都应该热更新

Nacos 支持配置动态刷新,这是它非常有价值的能力。

但动态刷新也存在风险。

适合动态刷新的配置包括:

  • 功能开关;
  • 展示参数;
  • 限流阈值;
  • 超时时间;
  • 灰度比例;
  • 非核心业务参数;
  • 告警阈值;
  • 缓存过期时间。

不建议随意动态刷新的配置包括:

  • 数据库连接地址;
  • 数据库驱动;
  • 数据源类型;
  • Redis 集群拓扑;
  • RocketMQ NameServer 拓扑;
  • Web 容器底层参数;
  • 核心线程池结构;
  • 安全密钥;
  • 序列化协议;
  • 数据一致性模式。

原因是这些参数改变后,往往需要:

  • 重建连接池;
  • 重建客户端;
  • 重启 Bean;
  • 重新初始化资源;
  • 验证兼容性;
  • 进行发布级测试。

因此,我通常把配置分为三类:

类型 处理方式
安全动态配置 允许自动刷新
受控动态配置 审批后刷新并监控
启动级配置 修改后重新发布或重启

十七、配置刷新代码示例

对于允许动态刷新的配置,可以使用配置属性类统一管理。

@Data
@Component
@ConfigurationProperties(prefix = "trade.order")
@RefreshScope
public class OrderProperties {

    /**
     * 订单自动关闭分钟数
     */
    private Integer autoCloseMinutes = 30;

    /**
     * 是否开启库存预占
     */
    private Boolean stockReserveEnabled = true;

    /**
     * 单用户最大待支付订单数
     */
    private Integer maxPendingOrderCount = 20;
}

业务中使用:

@Service
@RequiredArgsConstructor
public class OrderCreateService {

    private final OrderProperties orderProperties;

    public void validatePendingOrderCount(int currentCount) {
        Integer maxCount =
            orderProperties.getMaxPendingOrderCount();

        if (currentCount >= maxCount) {
            throw new BusinessException(
                "待支付订单数量已达到上限"
            );
        }
    }
}

这里需要注意两个问题。

第一,不要到处直接读取配置字符串

不建议:

@Value("${trade.order.max-pending-order-count}")
private Integer maxPendingOrderCount;

大量分散的 @Value 会导致:

  • 配置缺少统一结构;
  • 默认值难管理;
  • 类型校验不足;
  • 配置使用位置难追踪;
  • 重构成本增加。

更推荐通过 @ConfigurationProperties 按领域组织。

第二,动态配置必须提供默认值和校验

不能假设配置中心永远有正确值。

@Data
@Validated
@Component
@ConfigurationProperties(prefix = "trade.order")
public class OrderProperties {

    @Min(1)
    @Max(1440)
    private Integer autoCloseMinutes = 30;

    @Min(1)
    @Max(100)
    private Integer maxPendingOrderCount = 20;
}

错误配置不应悄悄进入系统。


十八、敏感配置如何处理

以下内容属于敏感配置:

数据库密码
Redis 密码
RocketMQ 认证信息
AccessKey
SecretKey
JWT 密钥
支付密钥
短信平台密钥
对象存储密钥
第三方接口密钥
私钥证书

不建议直接明文保存在:

  • Git 仓库;
  • 普通 YAML 文件;
  • Nacos 公共配置;
  • Wiki 文档;
  • 部署脚本;
  • 聊天记录。

推荐方式包括:

环境变量
Docker Secret
Kubernetes Secret
独立密钥管理系统
加密配置
最小权限账号
定期轮换
访问审计

例如:

spring:
  datasource:
    username: ${DB_USERNAME}
    password: ${DB_PASSWORD}

  data:
    redis:
      password: ${REDIS_PASSWORD}

Nacos 中可以保存变量引用和非敏感地址,但真正密码由部署环境注入。

我的基本原则是:

配置中心负责配置治理,密钥系统负责秘密管理,两者不要混为一谈。


十九、配置变更必须具备审计和回滚能力

生产配置修改属于发布行为,不应被当成普通文本编辑。

每一次配置变更至少应记录:

谁修改
什么时候修改
修改了哪个环境
修改了哪个 Data ID
修改前内容
修改后内容
修改原因
关联工单
验证结果
是否回滚

推荐变更流程

提出变更
   ↓
评审影响范围
   ↓
确认是否支持动态刷新
   ↓
备份当前配置
   ↓
测试环境验证
   ↓
预发布环境验证
   ↓
生产灰度发布
   ↓
监控核心指标
   ↓
全量发布或回滚

不建议的方式

直接登录生产 Nacos
   ↓
在线修改
   ↓
点击发布
   ↓
等待用户反馈

这种方式没有:

  • 影响评估;
  • 审批记录;
  • 灰度验证;
  • 回滚预案;
  • 监控观察。

二十、Nacos 配置灰度设计

配置灰度适合以下场景:

  • 新业务开关;
  • 新限流阈值;
  • 新路由规则;
  • 新缓存参数;
  • 新接口超时;
  • 新功能比例;
  • 部分实例验证。

灰度的目标不是“少量发布”这么简单,而是:

在控制影响范围的前提下验证配置是否正确。

典型流程:

选择一组灰度实例
       ↓
发布灰度配置
       ↓
观察错误率和响应时间
       ↓
观察业务结果
       ↓
确认无异常
       ↓
扩大范围
       ↓
全量发布

灰度期间重点关注:

  • 实例是否正确接收配置;
  • 配置是否真正生效;
  • 错误率是否上升;
  • P95、P99 是否变化;
  • Redis 和数据库负载是否变化;
  • 消息堆积是否变化;
  • 业务数据是否异常。

二十一、Nacos 生产集群设计

本地开发环境可以使用单节点。

但生产环境不建议依赖单节点 Nacos。

推荐生产结构

                负载均衡入口
                     │
        ┌────────────┼────────────┐
        │            │            │
   Nacos-01      Nacos-02      Nacos-03
        │            │            │
        └────────────┼────────────┘
                     │
                 MySQL 集群

主要设计点包括:

不少于三个 Nacos 节点
节点分布到不同宿主机
外置 MySQL 数据库
数据库定期备份
统一访问入口
节点健康检查
监控和告警
配置数据备份
升级和回滚方案

为什么不建议两个节点

两个节点很难形成稳定的多数派机制。

从高可用和一致性角度看,三个节点通常比两个节点更合理。

Nacos 2.x 网络端口

Nacos 2.x 除了常用的 HTTP 端口,还涉及客户端通信和节点通信端口。

在 Docker、Kubernetes、防火墙和负载均衡配置中,不能只开放 8848

应根据实际部署方式确认:

8848
9848
9849

以及集群内部需要的相关通信端口。

很多“控制台能打开,但客户端注册失败”的问题,本质上不是应用配置错误,而是 gRPC 通信端口没有正确开放或转发。


二十二、Nacos 与 Docker、Kubernetes 的结合

Docker Compose 示例结构

services:
  nacos-1:
    image: nacos/nacos-server
    environment:
      MODE: cluster
      NACOS_SERVERS: nacos-1:8848 nacos-2:8848 nacos-3:8848
      SPRING_DATASOURCE_PLATFORM: mysql
    ports:
      - "8848:8848"
      - "9848:9848"
      - "9849:9849"

  nacos-2:
    image: nacos/nacos-server
    environment:
      MODE: cluster

  nacos-3:
    image: nacos/nacos-server
    environment:
      MODE: cluster

正式配置还需要补充:

  • MySQL 地址;
  • 数据库名称;
  • 数据库账号密码;
  • JVM 参数;
  • 日志目录;
  • 数据目录;
  • 网络配置;
  • 健康检查;
  • 资源限制。

Kubernetes 场景

在 Kubernetes 中需要重点考虑:

  • StatefulSet;
  • Headless Service;
  • 固定节点标识;
  • PVC;
  • ConfigMap;
  • Secret;
  • Readiness Probe;
  • Liveness Probe;
  • PodDisruptionBudget;
  • 节点反亲和;
  • 数据库外置;
  • 滚动升级策略。

即使 Kubernetes 自身具备服务发现能力,Nacos 仍然可能承担:

  • Spring Cloud 服务治理;
  • 配置中心;
  • 非 Kubernetes 服务发现;
  • 多环境统一治理;
  • 灰度元数据;
  • 跨平台服务注册。

是否同时使用 Kubernetes Service 与 Nacos,应根据系统边界和团队治理方式确定,而不是简单二选一。


二十三、客户端容灾必须考虑本地缓存

Nacos 短时不可用时,业务服务不应立即全部瘫痪。

正常情况下,客户端会保留一定的本地服务列表和配置缓存。

这意味着:

  • 已经运行的服务可能仍能继续调用已有实例;
  • 已加载配置可能仍能继续使用;
  • 新实例注册和变更推送会受到影响;
  • 新启动服务可能无法正常获取完整治理信息。

因此,Nacos 故障后的真实影响要分情况判断。

场景 可能影响
已运行服务调用已有实例 可能继续运行
新服务启动 可能失败或配置不完整
新实例注册 可能失败
实例上下线通知 可能延迟
动态配置发布 无法正常下发
灰度规则变更 无法及时生效

这也是为什么我不会把 Nacos 故障简单描述成“所有服务立刻全部不可用”。

真正需要设计的是:

本地缓存
超时策略
重试策略
故障窗口
恢复流程
变更冻结
监控告警

二十四、Nacos 需要监控哪些指标

Nacos 上线后,不能只监控“进程是否存在”。

服务端指标

重点关注:

节点存活状态
CPU 使用率
内存使用率
JVM 堆内存
Full GC
线程数量
连接数量
请求错误率
请求耗时
配置发布失败
服务实例数量
数据库连接
数据库慢查询
节点间通信异常

客户端指标

重点关注:

注册是否成功
配置是否加载成功
配置刷新是否成功
服务列表是否更新
Nacos 请求超时
客户端重连次数
服务调用无实例异常
配置读取失败次数

业务侧异常

常见关键异常包括:

No instances available
Client not connected
Request nacos server failed
Config data not exist
TimeoutException
Connection refused
gRPC connection failed

监控平台应将 Nacos 日志、应用日志、Prometheus 指标和告警结合起来。


二十五、常见故障与排查方式

1. 服务没有注册到 Nacos

排查顺序:

检查 Nacos 地址
   ↓
检查 Namespace
   ↓
检查 Group
   ↓
检查用户名和密码
   ↓
检查网络和端口
   ↓
检查应用日志
   ↓
检查 Nacos 服务端日志

常见原因:

  • server-addr 错误;
  • Namespace 使用名称而不是正确 ID;
  • Nacos 认证失败;
  • 8848 或 gRPC 端口未开放;
  • 服务名称为空;
  • 客户端与服务端不兼容;
  • Docker 网络地址使用错误。

2. OpenFeign 提示没有可用实例

异常示例:

No instances available for order-service

重点检查:

  • 服务名称是否完全一致;
  • 消费者与提供者是否在同一 Namespace;
  • Group 是否匹配;
  • 提供者是否健康;
  • 是否注册到了错误环境;
  • 服务是否已经下线;
  • LoadBalancer 是否正常;
  • 灰度过滤条件是否过严。

3. Nacos 配置没有生效

重点检查:

  • Data ID 是否正确;
  • Group 是否正确;
  • Namespace 是否正确;
  • 文件扩展名是否一致;
  • Profile 是否正确;
  • Config Import 是否加载;
  • 配置优先级是否被本地值覆盖;
  • 是否需要动态刷新;
  • 配置绑定前缀是否正确。

4. 修改配置后应用没有刷新

重点检查:

  • 配置项是否允许刷新;
  • refreshEnabled 是否开启;
  • Bean 是否支持刷新;
  • 是否使用了正确的配置绑定方式;
  • 配置值是否被代码常量缓存;
  • 是否需要重新初始化客户端;
  • 当前配置是否属于启动级配置。

5. 控制台可以访问,但客户端连接失败

重点检查:

8848 是否可达
9848 是否可达
反向代理是否支持对应通信
Docker 端口是否映射
防火墙是否开放
客户端访问地址是否正确

Nacos 2.x 中,这类问题经常与 gRPC 通信端口有关。


二十六、我在项目中坚持的 Nacos 设计原则

结合长期 Java 微服务项目实践,我通常坚持以下原则。

原则一:环境必须物理或逻辑强隔离

local、dev、test、staging、prod

不能只靠开发人员“注意不要配错”。


原则二:配置按职责拆分

应用配置
公共技术配置
业务域配置
敏感配置

不能全部堆进一个大 YAML。


原则三:生产配置变更等同于发布

需要:

评审
审批
备份
灰度
监控
回滚
审计

原则四:不是所有配置都动态刷新

底层连接、核心安全和基础设施配置应采用更谨慎的发布方式。


原则五:敏感信息不直接明文保存

配置中心不能替代专业密钥管理。


原则六:生产必须集群化

单节点可以用于本地和临时测试,不应成为生产长期方案。


原则七:必须具备故障预案

需要明确:

  • Nacos 单节点故障;
  • 集群故障;
  • 数据库故障;
  • 配置误发布;
  • 网络中断;
  • 认证异常;
  • 升级失败;

分别怎么处理。


二十七、Nacos 企业级验收清单

注册中心验收

  • 服务能否正常注册;
  • 服务下线后能否及时摘除;
  • 多实例能否正确发现;
  • Namespace 是否严格隔离;
  • Group 是否符合规划;
  • Cluster 是否符合部署拓扑;
  • Metadata 是否可用于灰度;
  • OpenFeign 是否能正确发现实例;
  • Gateway 是否能正确动态路由。

配置中心验收

  • Data ID 是否统一命名;
  • 配置是否按职责拆分;
  • 公共配置是否合理共享;
  • 应用配置是否保持独立;
  • 动态刷新是否经过验证;
  • 启动级配置是否禁止随意刷新;
  • 配置是否具备默认值;
  • 配置参数是否具备校验;
  • 敏感信息是否被安全管理。

安全治理验收

  • 是否开启认证;
  • 是否修改默认账号密码;
  • 是否限制控制台访问来源;
  • 是否配置最小权限;
  • 是否记录配置变更;
  • 是否避免明文密钥;
  • 是否具备账号轮换机制;
  • 是否具备操作审计。

高可用验收

  • 是否至少部署三个节点;
  • 是否分布在不同宿主机;
  • 是否使用外置数据库;
  • 数据库是否具备备份;
  • 节点故障后是否仍可访问;
  • 端口和网络是否完整;
  • 是否具备监控和告警;
  • 是否完成配置备份;
  • 是否具备升级与回滚方案。

故障演练验收

至少演练:

停止一个 Nacos 节点
停止两个 Nacos 节点
阻断客户端到 Nacos 网络
发布一条错误配置
回滚错误配置
重启业务服务
重新注册服务实例
恢复 Nacos 集群

真正的高可用不是写在架构图里,而是通过故障演练验证出来。


二十八、常见设计误区

误区一:所有环境共用 public Namespace

这样做会增加跨环境调用和配置污染风险。


误区二:所有服务都使用 DEFAULT_GROUP

项目规模扩大后,很难按业务域治理。


误区三:所有配置放在一个文件中

任何修改都可能影响整个服务,回滚粒度也过大。


误区四:所有配置都开启动态刷新

底层连接和核心安全配置错误刷新后,可能直接造成生产故障。


误区五:把数据库密码直接写进 Nacos

配置集中不等于敏感信息安全。


误区六:生产使用单节点 Nacos

一旦节点、宿主机或磁盘故障,注册和配置治理能力都会受到影响。


误区七:只关注控制台,不关注客户端状态

控制台可访问,不代表业务服务一定注册成功、配置一定加载成功。


误区八:Nacos 故障时让业务服务无限重试

无限重试可能造成:

  • 线程占用;
  • 日志爆炸;
  • 网络压力;
  • 启动阻塞;
  • 故障放大。

应设置合理的超时、重试和降级策略。


二十九、总结

从我的项目实践来看,Nacos 的价值从来不只是“服务注册”和“配置集中”。

真正的企业级 Nacos 应具备:

环境隔离
服务治理
配置分类
动态刷新
权限控制
敏感信息保护
灰度发布
变更审计
快速回滚
集群高可用
监控告警
故障恢复

本文需要重点记住以下结论:

  1. Nacos 是服务治理和配置治理基础设施,不是业务数据库。
  2. Namespace 优先用于环境隔离。
  3. Group 用于同一环境内的业务域和配置分类。
  4. Service 名称应统一、稳定、可识别。
  5. Cluster 应服务于真实地域、机房和部署拓扑。
  6. Metadata 是版本、灰度和流量泳道的重要基础。
  7. 配置中心不是简单地把本地 YAML 搬到控制台。
  8. 配置应按应用、公共技术、业务域和敏感级别拆分。
  9. 不是所有配置都适合动态刷新。
  10. 敏感信息应由环境变量、Secret 或密钥系统管理。
  11. 生产配置变更必须具备评审、灰度、监控、审计和回滚。
  12. 生产环境应采用 Nacos 集群和外置数据库。
  13. Nacos 高可用必须通过故障演练进行验证。

最后,用一句话概括:

Nacos 接入只是起点,环境不串、配置可控、变更可追、故障可恢复,才是企业级注册中心和配置中心真正的落地标准。


下一篇预告

下一篇将继续介绍:

《微服务架构高级应用(四):Spring Cloud Gateway 统一网关企业级设计》

主要内容包括:

  • Gateway 在微服务架构中的职责边界;
  • 动态路由和 Nacos 路由配置;
  • JWT 认证与用户上下文透传;
  • 租户上下文和数据权限透传;
  • 黑白名单;
  • IP、用户、接口和租户限流;
  • 请求签名与防重放攻击;
  • TraceId 注入;
  • 统一异常和访问日志;
  • 灰度发布与流量泳道;
  • WebSocket、文件上传和大请求处理;
  • Gateway 高可用部署;
  • 网关常见性能问题;
  • 生产验收和故障排查清单。

更多推荐