Nacos服务发现与配置中心:微服务注册中心实战
**作者:洛水石** | **更新日期:2026-05-11** | **标签:Nacos | Spring Cloud | 微服务 | 服务治理**
前言
上周二早上9点,线上告警炸了:服务A调用服务B失败,500+错误。查了半天发现是服务B重启后IP变了,服务A还在用旧的IP调用。
这不是个案。在微服务架构中,**服务实例是动态的**,IP会变、端口会变、数量会动态伸缩。传统的配置文件方式根本无法应对这种变化。
Nacos就是来解决这个问题的——**服务注册与发现、配置管理、服务健康监测**,让你告别硬编码,拥抱动态服务治理。
一、Nacos核心概念
1.1 服务注册与发现原理
▲ Nacos服务注册发现架构
**核心流程**:
- 服务提供者启动时向Nacos注册自己的信息
- 服务消费者从Nacos获取服务提供者的实例列表
- Nacos感知到服务变化时主动通知消费者
1.2 命名空间与隔离
隔离级别 | 说明 | 使用场景 |
**Namespace** | 顶级隔离,不同环境 | dev/test/prod |
**Group** | 服务分组 | 业务线/团队划分 |
**DataID** | 具体配置 | 配置文件 |
二、快速部署
2.1 Docker Compose部署
# docker-compose.yml
version: '3.8'
services:
nacos:
image: nacos/nacos-server:v2.2.3
container_name: nacos
environment:
MODE: standalone
SPRING_DATASOURCE_PLATFORM: embedded
ports:
- "8848:8848"
- "9848:9848"
volumes:
- ./data:/home/nacos/data
- ./logs:/home/nacos/logs
restart: unless-stopped
# 启动
docker-compose up -d
# 访问控制台
# http://localhost:8848/nacos
# 默认账号密码: nacos / nacos
2.2 Kubernetes部署
# nacos.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: nacos-standalone-config
data:
MODE: "standalone"
---
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: nacos
spec:
serviceName: nacos
replicas: 1
selector:
matchLabels:
app: nacos
template:
metadata:
labels:
app: nacos
spec:
containers:
- name: nacos
image: nacos/nacos-server:v2.2.3
ports:
- containerPort: 8848
name: client
- containerPort: 9848
name: grpc
env:
- name: MODE
valueFrom:
configMapKeyRef:
name: nacos-standalone-config
key: MODE
resources:
requests:
memory: 1Gi
cpu: 500m
limits:
memory: 2Gi
cpu: 1000m
三、Spring Boot集成
3.1 依赖配置
<!-- pom.xml -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
<version>2022.0.0.0</version>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
<version>2022.0.0.0</version>
</dependency>
3.2 application.yml
# bootstrap.yml (注意是bootstrap不是application)
spring:
application:
name: order-service
cloud:
nacos:
server-addr: 192.168.1.100:8848
username: nacos
password: nacos
discovery:
namespace: dev
group: DEFAULT_GROUP
metadata:
version: v1
config:
namespace: dev
group: DEFAULT_GROUP
file-extension: yaml
refresh-enabled: true
shared-configs:
->group: GLOBAL
refresh: true
3.3 服务注册
@SpringBootApplication
@EnableDiscoveryClient // 启用服务发现
public class OrderServiceApplication {
public static void main(String[] args) {
SpringApplication.run(OrderServiceApplication.class, args);
}
}
// 服务启动后自动注册到Nacos
@RestController
public class HealthController {
@GetMapping("/health")
public String health() {
return "OK";
}
}
3.4 服务调用
@Service
public class OrderService {
@Autowired
private RestTemplate restTemplate;
// 方式1:服务名直接调用(Ribbon负载均衡)
@Bean
@LoadBalanced
public RestTemplate restTemplate() {
return new RestTemplate();
}
public Order createOrder(Long productId, Integer quantity) {
// 通过服务名调用,不需要知道IP和端口
Product product = restTemplate.getForObject(
"http://product-service/api/products/" + productId,
Product.class
);
// ... 创建订单
return order;
}
}
3.5 使用Feign调用
// 定义Feign客户端
@FeignClient(name = "product-service", path = "/api/products")
public interface ProductClient {
@GetMapping("/{id}")
Product getProduct(@PathVariable("id") Long id);
@GetMapping("/{id}/stock")
Integer getStock(@PathVariable("id") Long id);
}
// 使用
@Service
public class OrderService {
@Autowired
private ProductClient productClient;
public Order createOrder(Long productId) {
Product product = productClient.getProduct(productId);
// ... 创建订单
return order;
}
}
四、配置中心
4.1 在Nacos创建配置
▲ 配置中心工作流程
# Data ID: order-service.yaml
# Group: DEFAULT_GROUP
# Namespace: dev
spring:
datasource:
url: jdbc:mysql://mysql:3306/orders?useSSL=false
username: root
password: ${DB_PASSWORD:default123}
driver-class-name: com.mysql.cj.jdbc.Driver
server:
port: ${SERVER_PORT:8080}
order:
timeout: 5000
max-retry: 3
payment-url: http://payment-service/api/pay
4.2 动态获取配置
@RestController
@RefreshScope // 启用动态刷新
public class OrderConfig {
@Value("${order.timeout:3000}")
private Integer timeout;
@Value("${order.max-retry:3}")
private Integer maxRetry;
@GetMapping("/config")
public Map<String, Object> getConfig() {
Map<String, Object> config = new HashMap<>();
config.put("timeout", timeout);
config.put("maxRetry", maxRetry);
return config;
}
}
4.3 配置监听
@Component
@Slf4j
public class NacosConfigListener {
@NacosConfigListener(dataId = "order-service.yaml", groupId = "DEFAULT_GROUP")
public void onConfigChange(String config) {
log.info("配置变更: {}", config);
// 处理配置变更
// 例如:重新初始化连接池、刷新缓存等
}
}
4.4 共享配置
# 共享配置 - 多个服务共用
# Data ID: common.yaml
# Group: GLOBAL
# 日志配置
logging:
level:
root: INFO
com.example: DEBUG
pattern:
console: "%d{yyyy-MM-dd HH:mm:ss} [%thread] %-5level %logger{36} - %msg%n"
# Swagger配置
swagger:
enabled: true
title: API文档
version: 1.0
五、服务治理
5.1 负载均衡权重
// 服务实例级别设置权重
@Configuration
public class RibbonConfig {
@Bean
public IRule ribbonRule() {
// 权重负载均衡 - 根据权重分配流量
return new WeightedResponseTimeRule();
}
}
5.2 熔断降级
@FeignClient(name = "product-service", fallback = ProductClientFallback.class)
public interface ProductClient {
@GetMapping("/{id}")
Product getProduct(@PathVariable("id") Long id);
}
// 降级实现
@Component
@Slf4j
public class ProductClientFallback implements ProductClient {
@Override
public Product getProduct(Long id) {
log.warn("Product服务调用失败,返回降级数据");
Product fallbackProduct = new Product();
fallbackProduct.setId(id);
fallbackProduct.setName("降级商品");
fallbackProduct.setPrice(BigDecimal.ZERO);
return fallbackProduct;
}
}
5.3 命名空间隔离
# bootstrap.yml
spring:
cloud:
nacos:
discovery:
namespace: ${NACOS_NAMESPACE} # 指定命名空间
group: ${SERVICE_GROUP} # 指定分组
// Java中获取某命名空间的服务
@Autowired
private NamingService namingService;
public List<Instance> getInstances(String serviceName) {
try {
return namingService.selectInstances(serviceName, true);
} catch (NacosException e) {
log.error("获取服务实例失败", e);
return Collections.emptyList();
}
}
六、生产最佳实践
6.1 高可用部署
▲ Nacos高可用集群架构
# nacos-cluster.yaml
version: '3.8'
services:
nacos1:
image: nacos/nacos-server:v2.2.3
container_name: nacos1
environment:
MODE: cluster
NACOS_SERVERS: nacos1:8848 nacos2:8848 nacos3:8848
MYSQL_HOST: mysql
MYSQL_DB_NAME: nacos
MYSQL_USER: nacos
MYSQL_PASSWORD: nacos123
ports:
- "8848:8848"
depends_on:
- mysql
nacos2:
image: nacos/nacos-server:v2.2.3
container_name: nacos2
environment:
MODE: cluster
NACOS_SERVERS: nacos1:8848 nacos2:8848 nacos3:8848
MYSQL_HOST: mysql
MYSQL_DB_NAME: nacos
MYSQL_USER: nacos
MYSQL_PASSWORD: nacos123
ports:
- "8849:8848"
nacos3:
image: nacos/nacos-server:v2.2.3
container_name: nacos3
environment:
MODE: cluster
NACOS_SERVERS: nacos1:8848 nacos2:8848 nacos3:8848
MYSQL_HOST: mysql
MYSQL_DB_NAME: nacos
MYSQL_USER: nacos
MYSQL_PASSWORD: nacos123
ports:
- "8850:8848"
mysql:
image: mysql:8.0
environment:
MYSQL_ROOT_PASSWORD: root123
MYSQL_DATABASE: nacos
volumes:
- mysql_data:/var/lib/mysql
volumes:
mysql_data:
6.2 配置加密
// 配置属性加密
@Configuration
public class NacosConfig {
@NacosConfigurationProperties(prefix = "spring.datasource")
public DataSourceProperties dataSourceProperties() {
return new DataSourceProperties();
}
}
// 使用加密配置
spring:
datasource:
password: '{cipher}xxx加密后的密码xxx'
七、常见问题
Q1: 服务注册后发现实例不存在?
# 检查网络连通性
curl http://192.168.1.100:8848/nacos/v1/ns/instance/list?serviceName=order-service
# 检查服务实例元数据
curl http://192.168.1.100:8848/nacos/v1/ns/instance/metadata?serviceName=order-service
Q2: 配置更新后没有生效?
// 检查是否添加了 @RefreshScope
@RestController
@RefreshScope // 必须添加!
public class ConfigController {
@Value("${custom.config}")
private String config;
}
Q3: 服务下线后仍被调用?
// 确保正确下线
@PreDestroy
public void deregister() {
try {
nacosServiceManager.getNamingService().deregisterInstance(
serviceName, ip, port
);
} catch (NacosException e) {
log.error("服务注销失败", e);
}
}
总结
Nacos核心能力一览:
能力 | 说明 | 收益 |
**服务注册** | 自动注册、心跳检测 | 免去手动维护服务列表 |
**服务发现** | 动态获取、实时通知 | 告别硬编码IP |
**配置管理** | 集中管理、动态刷新 | 配置变更无需重启 |
**命名空间** | 环境隔离、逻辑分区 | 支持多环境部署 |
**高可用** | 集群模式、数据持久化 | 生产环境必备 |
**下一步建议**:
- 集成Sentinel实现流量控制
- 接入SkyWalking实现链路追踪
- 配置Prometheus监控
*微服务架构,Nacos让服务治理变得简单。*
