在微服务架构中,配置管理与服务发现是基础设施的核心能力。Nacos 作为阿里巴巴开源的动态服务发现、配置管理和服务管理平台,已成为 Spring Cloud Alibaba 生态的首选组件。
一、Nacos 核心架构
1.1 两大核心能力
┌─────────────────────────────────────────────┐
│ Nacos Server │
├──────────────────────┬──────────────────────┤
│ 配置管理 (Config) │ 服务发现 (Naming) │
│ - 动态配置推送 │ - 服务注册 │
│ - 配置版本历史 │ - 健康检查 │
│ - 灰度发布 │ - 负载均衡 │
│ - 多环境隔离 │ - 服务元数据 │
└──────────────────────┴──────────────────────┘
1.2 数据一致性模型
| 模块 | 一致性协议 | 数据存储 |
|---|---|---|
| 配置管理 | Raft(CP) | Derby/MySQL |
| 服务发现 | Distro(AP) | 内存 + 持久化 |
Distro 协议是阿里巴巴自研的 AP 协议,专为服务发现的高可用场景设计。
二、配置中心实战
2.1 基础集成
# bootstrap.yml(或 application.yml)
spring:
application:
name: order-service
profiles:
active: dev
cloud:
nacos:
config:
server-addr: 127.0.0.1:8848
namespace: ${spring.profiles.active}
group: DEFAULT_GROUP
file-extension: yaml
# 共享配置
shared-configs:
- data-id: common.yaml
group: DEFAULT_GROUP
refresh: true
discovery:
server-addr: 127.0.0.1:8848
namespace: ${spring.profiles.active}
2.2 配置热更新
@RestController
@RefreshScope // 关键注解:支持配置动态刷新
public class OrderController {
@Value("${order.timeout:5000}")
private Integer timeout;
@Value("${order.max-retry:3}")
private Integer maxRetry;
@GetMapping("/config")
public Map<String, Object> getConfig() {
return Map.of(
"timeout", timeout,
"maxRetry", maxRetry
);
}
}
2.3 多环境配置管理
# Nacos 控制台配置 Data ID 命名规则
# ${prefix}-${spring.profiles.active}.${file-extension}
# 示例配置列表:
# order-service.yaml # 默认配置
# order-service-dev.yaml # 开发环境
# order-service-test.yaml # 测试环境
# order-service-prod.yaml # 生产环境
# common.yaml # 共享配置
2.4 灰度配置发布
@Configuration
public class GrayConfig {
@NacosValue(value = "${feature.new-payment-gateway:false}", autoRefreshed = true)
private boolean newPaymentGateway;
@NacosValue(value = "${gray.user.percent:0}", autoRefreshed = true)
private int grayPercent;
public boolean enableNewGateway(String userId) {
if (!newPaymentGateway) return false;
// 按用户 ID hash 取模实现灰度
int hash = Math.abs(userId.hashCode()) % 100;
return hash < grayPercent;
}
}
三、服务发现与负载均衡
3.1 服务注册
@SpringBootApplication
@EnableDiscoveryClient
public class OrderServiceApplication {
public static void main(String[] args) {
SpringApplication.run(OrderServiceApplication.class, args);
}
}
3.2 自定义负载均衡
@Component
public class NacosLoadBalancerConfig {
@Bean
public ReactorLoadBalancer<ServiceInstance> nacosLoadBalancer(
Environment env,
LoadBalancerClientFactory factory) {
String name = env.getProperty(LoadBalancerClientFactory.PROPERTY_NAME);
return new NacosLoadBalancer(
factory.getLazyProvider(name, ServiceInstanceListSupplier.class),
name
);
}
}
// 基于权重的自定义负载均衡
public class NacosLoadBalancer implements ReactorLoadBalancer<ServiceInstance> {
@Override
public Mono<Response<ServiceInstance>> choose(Request request) {
return supplier.get().next().map(instances -> {
// Nacos 实例自带权重 weight(0~1)
List<ServiceInstance> healthy = instances.stream()
.filter(i -> "true".equals(i.getMetadata().get("nacos.healthy")))
.collect(Collectors.toList());
// 按权重随机选择
double totalWeight = healthy.stream()
.mapToDouble(i -> Double.parseDouble(i.getMetadata().get("nacos.weight")))
.sum();
double random = ThreadLocalRandom.current().nextDouble(totalWeight);
for (ServiceInstance instance : healthy) {
random -= Double.parseDouble(instance.getMetadata().get("nacos.weight"));
if (random <= 0) return new DefaultResponse(instance);
}
return new DefaultResponse(healthy.get(0));
});
}
}
3.3 服务元数据与版本路由
# application.yml
spring:
cloud:
nacos:
discovery:
metadata:
version: v2 # 版本标识
region: cn-hangzhou # 地域标识
protocol: http # 协议标识
// 基于元数据的服务筛选
@FeignClient(name = "payment-service",
fallbackFactory = PaymentFallbackFactory.class,
configuration = VersionFeignConfig.class)
public interface PaymentClient {
@PostMapping("/pay")
PaymentResult pay(@RequestBody PaymentRequest req);
}
// 只调用 v2 版本的实例
public class VersionFeignConfig {
@Bean
public RequestInterceptor versionInterceptor() {
return template -> template.header("X-Target-Version", "v2");
}
}
四、Nacos 集群与高可用
4.1 集群部署架构
# cluster.conf(三台节点)
192.168.1.101:8848
192.168.1.102:8848
192.168.1.103:8848
4.2 嵌入式 vs 外置存储
| 模式 | 数据存储 | 适用场景 |
|---|---|---|
| 单例 | 内嵌 Derby | 开发测试 |
| 集群(内置) | 内嵌 Derby + Raft | 小型集群 |
| 集群(外置) | MySQL 8.0 | 生产环境 |
# application.properties(外置 MySQL)
spring.datasource.platform=mysql
db.num=1
db.url.0=jdbc:mysql://127.0.0.1:3306/nacos?characterEncoding=utf8
db.user.0=nacos
db.password.0=nacos
4.3 配置持久化与历史版本
// 监听配置变更历史
@NacosConfigListener(dataId = "order-service.yaml", groupId = "DEFAULT_GROUP")
public void onChange(String config) {
log.info("配置已更新: {}", config);
}
// Nacos 控制台支持:配置回滚、版本对比、变更审计
五、最佳实践
5.1 配置分层设计
配置分层:
├── 基础层(common.yaml) # 所有服务共享:数据库连接池、日志级别
├── 服务层({service}.yaml) # 单个服务配置:业务参数、开关
├── 环境层({service}-{env}.yaml) # 环境差异:超时时间、线程池大小
└── 临时层(Nacos 控制台热改) # 紧急调整:限流阈值、降级开关
5.2 敏感配置加密
# 加密配置(Nacos 2.x 支持 AES 加密)
order:
db:
password: ENC(加密后的密文)
@Configuration
public class EncryptConfig {
@Bean
public StringEncryptor stringEncryptor() {
return new AESStringEncryptor(new SimpleAESConfig(
System.getenv("NACOS_ENCRYPT_KEY")
));
}
}
5.3 配置变更通知
@Component
public class ConfigChangeListener {
@Autowired
private ThreadPoolExecutor executor;
@NacosConfigListener(dataId = "thread-pool.yaml")
public void onThreadPoolConfigChange(String config) {
ThreadPoolConfig cfg = YamlUtils.parse(config, ThreadPoolConfig.class);
// 动态调整线程池参数
executor.setCorePoolSize(cfg.getCoreSize());
executor.setMaximumPoolSize(cfg.getMaxSize());
executor.setKeepAliveTime(cfg.getKeepAlive(), TimeUnit.SECONDS);
}
}
六、Nacos vs 其他注册中心
| 特性 | Nacos | Eureka | Consul | ZooKeeper |
|---|---|---|---|---|
| 配置中心 | 内置 | 无(需 Config Server) | 支持 | 无 |
| 健康检查 | TCP/HTTP/MYSQL | 客户端心跳 | 多种协议 | 临时节点 |
| 负载均衡 | 权重 + 元数据 | Ribbon | Fabio | 需自研 |
| 一致性 | CP + AP | AP | CP | CP |
| 性能(QPS) | 10w+ | 较低 | 中等 | 中等 |
| Spring Cloud | Alibaba 官方 | Netflix(停止维护) | 社区 | 需 Curator |
七、常见问题
7.1 配置不生效排查
# 1. 检查客户端日志
grep -i "nacos" logs/spring.log
# 2. 确认 Data ID 格式
# 正确的:order-service-dev.yaml
# 错误的:order-service-dev.yml(后缀不匹配)
# 3. 检查 namespace/group 是否匹配
7.2 服务注册不上
// 常见原因:
// 1. @EnableDiscoveryClient 缺失
// 2. 包扫描路径错误
// 3. 网络不通(防火墙、安全组)
// 4. 元数据过大会导致注册失败(限制 32KB)
7.3 长连接与推送
# Nacos 2.x 使用 gRPC 长连接替代 HTTP 轮询
server:
grpc:
port: 9848 # gRPC 端口(Nacos 2.x 默认)
八、总结
| 能力 | 关键配置 | 注意事项 |
|---|---|---|
| 配置管理 | shared-configs、namespace | 注意 Data ID 命名规则 |
| 服务发现 | metadata、weight | 健康检查配置合理 |
| 灰度发布 | 动态配置 + 业务判断 | 配置变更需幂等 |
| 集群部署 | MySQL 外置存储 | 至少 3 节点保证 Raft |
Nacos 将配置管理与服务发现统一,降低了微服务基础设施的复杂度。在生产环境中,建议配置外置存储、开启鉴权、做好集群规划。
继续阅读
探索更多技术文章
浏览归档,发现更多关于系统设计、工具链和工程实践的内容。