Nacos 服务注册发现
Nacos 简介
Nacos(Naming and Configuration Service)是阿里巴巴开源的动态服务发现、配置管理和服务管理平台。
核心概念
- 服务(Service):Nacos 服务治理的基本单元
- 服务实例(Instance):提供具体服务的节点
- 命名空间(Namespace):用于环境隔离,如 dev/test/prod
- 分组(Group):用于服务分组,默认 DEFAULT_GROUP
- 集群(Cluster):服务实例的逻辑分组
- 元数据(Metadata):服务的附加信息
工作原理
┌─────────────┐ 注册 ┌─────────────┐
│ 服务提供者 │ ──────────────> │ Nacos │
│ Provider │ │ Server │
└─────────────┘ └─────────────┘
│
│ 查询
▼
┌─────────────┐ ┌─────────────┐
│ 服务消费者 │ <────────────── │ Nacos │
│ Consumer │ 返回实例列表 │ Server │
└─────────────┘ └─────────────┘
快速开始
1. 添加依赖
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
2. 配置 Nacos
spring:
application:
name: user-service
cloud:
nacos:
discovery:
server-addr: localhost:8848
namespace: public
group: DEFAULT_GROUP
cluster-name: DEFAULT
register-enabled: true
watch-enabled: true
3. 启用服务发现
@SpringBootApplication
@EnableDiscoveryClient
public class UserServiceApplication {
public static void main(String[] args) {
SpringApplication.run(UserServiceApplication.class, args);
}
}
4. 服务调用
@RestController
public class UserController {
@Autowired
private DiscoveryClient discoveryClient;
@GetMapping("/users/{id}")
public User getUser(@PathVariable Long id) {
// 获取服务实例列表
List<ServiceInstance> instances =
discoveryClient.getInstances("order-service");
// 负载均衡选择实例
ServiceInstance instance = instances.get(0);
// 调用服务
String url = instance.getUri() + "/orders/" + id;
return restTemplate.getForObject(url, User.class);
}
}
高级特性
1. 命名空间隔离
使用命名空间实现环境隔离:
spring:
cloud:
nacos:
discovery:
server-addr: localhost:8848
namespace: 90a8c8b9-xxxx-xxxx-xxxx-xxxxxxxxxxxx # dev 环境
最佳实践:
- 为每个环境创建独立的命名空间
- 生产环境使用独立命名空间
- 避免使用 public 命名空间
2. 服务分组
使用分组实现服务版本管理:
spring:
cloud:
nacos:
discovery:
group: V1_GROUP # 或 V2_GROUP
使用场景:
- 灰度发布
- 多版本共存
- A/B 测试
3. 集群配置
将服务实例划分到不同集群:
spring:
cloud:
nacos:
discovery:
cluster-name: HANGZHOU # 杭州集群
跨集群调用:
@FeignClient(
name = "order-service",
configuration = FeignConfiguration.class
)
public interface OrderClient {
@GetMapping("/orders/{id}")
Result<Order> getOrder(@PathVariable("id") Long id);
}
@Configuration
public class FeignConfiguration {
@Bean
public Logger.Level feignLoggerLevel() {
return Logger.Level.BASIC;
}
}
4. 元数据管理
为服务实例添加元数据:
spring:
cloud:
nacos:
discovery:
metadata:
version: 1.0.0
region: hangzhou
zone: zone1
元数据使用:
// 基于元数据的路由规则
@Autowired
private DiscoveryClient discoveryClient;
public ServiceInstance selectInstance() {
List<ServiceInstance> instances =
discoveryClient.getInstances("order-service");
return instances.stream()
.filter(instance ->
"hangzhou".equals(instance.getMetadata().get("region"))
)
.findFirst()
.orElse(instances.get(0));
}
健康检查
Nacos 健康检查机制
Nacos 支持两种健康检查模式:
- 客户端模式:服务实例主动上报心跳
- 服务端模式:Nacos 主动探测服务实例
配置健康检查
spring:
cloud:
nacos:
discovery:
# 心跳间隔(毫秒)
heart-beat-interval: 5000
# 心跳超时时间(毫秒)
heart-beat-timeout: 15000
# IP 保护时间(毫秒)
ip-delete-timeout: 30000
自定义健康检查
@Component
public class CustomHealthCheck implements HealthCheckCallback {
@Override
public boolean doHealthCheck(String ip, int port) {
// 自定义健康检查逻辑
try {
String url = "http://" + ip + ":" + port + "/health";
ResponseEntity<String> response =
restTemplate.getForEntity(url, String.class);
return response.getStatusCode().is2xxSuccessful();
} catch (Exception e) {
return false;
}
}
}
服务监听
监听服务变化
@Component
public class ServiceChangeListener {
@Autowired
private DiscoveryClient discoveryClient;
@EventListener
public void onInstanceEvent(InstanceEvent event) {
if (event instanceof InstanceUpEvent) {
log.info("服务上线:{}", event.getServiceId());
} else if (event instanceof InstanceDownEvent) {
log.info("服务下线:{}", event.getServiceId());
}
}
}
负载均衡
集成 Spring Cloud LoadBalancer
@Configuration
public class LoadBalancerConfiguration {
@Bean
@LoadBalanced
public RestTemplate restTemplate() {
return new RestTemplate();
}
@Bean
public ReactorLoadBalancer<ServiceInstance> loadBalancer(
Environment environment,
LoadBalancerClientFactory loadBalancerClientFactory
) {
String name = environment.getProperty(LoadBalancerClientFactory.PROPERTY_NAME);
return loadBalancerClientFactory.getInstance(name);
}
}
自定义负载均衡策略
@Configuration
public class CustomLoadBalancerConfig {
@Bean
public ReactorServiceInstanceLoadBalancer loadBalancer() {
return serviceInstances -> {
List<ServiceInstance> list = serviceInstances.collectList().block();
if (list == null || list.isEmpty()) {
throw new NoServiceInstanceFoundException();
}
// 自定义选择逻辑
return Mono.just(list.get(0));
};
}
}
生产实践
1. 多注册中心配置
spring:
cloud:
nacos:
discovery:
server-addr:
- nacos1:8848
- nacos2:8848
- nacos3:8848
2. 服务优雅上下线
@Component
public class GracefulShutdown {
@Autowired
private NacosServiceRegistry serviceRegistry;
@Autowired
private NacosRegistration registration;
@PreDestroy
public void shutdown() {
// 优雅下线
serviceRegistry.deregister(registration);
log.info("服务已优雅下线");
}
}
3. 服务权重配置
spring:
cloud:
nacos:
discovery:
weight: 1.0 # 权重值,范围 0-1
4. 服务保护阈值
spring:
cloud:
nacos:
discovery:
protect-threshold: 0.2 # 保护阈值,低于此值不剔除实例
常见问题
1. 服务注册失败
问题:服务无法注册到 Nacos
排查步骤:
- 检查 Nacos 服务器是否正常运行
- 检查网络连通性
- 检查命名空间 ID 是否正确
- 检查服务名是否合法
2. 服务发现延迟
问题:服务上线后,消费者不能立即发现
解决方案:
- 调整心跳间隔和超时时间
- 启用 Nacos 服务端主动探测
- 检查消费者缓存配置
3. 服务实例重复
问题:同一服务出现多个相同实例
解决方案:
- 检查服务 IP 配置
- 确保端口唯一
- 清理 Nacos 控制台的脏数据
总结
Nacos 作为服务注册中心,提供了服务自动注册与发现、健康检查、负载均衡等核心功能。
通过合理使用命名空间、分组、集群等特性,可以实现灵活的服务治理策略。
在生产环境中,建议配置合理的健康检查参数,并实现服务的优雅上下线,以提高系统的可用性。