Nacos 通过多重机制确保新注册的服务能够被及时发现。让我详细讲解其工作原理和保证机制:
一、核心发现流程
新服务注册 → Nacos Server → 服务发现客户端 → 缓存更新 → 负载均衡 → 流量转发
二、Nacos 服务发现保证机制
- 1注册中心层面的保证
bash
// Nacos Server 内部处理注册请求
public class ServiceManager {
public void registerInstance(Service service, Instance instance) {
// 1. 写入内存注册表
service.addInstance(instance);
// 2. 持久化到存储(如果是持久化实例)
if (instance.isEphemeral() == false) {
persistentServiceProcessor.process(service, instance);
}
// 3. 触发注册事件
NotifyCenter.publishEvent(new InstanceChangeEvent(service.getName()));
// 4. 集群间同步
raftCore.signalPublish(service, instance);
}
}
关键点:
• 内存注册表:实时更新,零延迟
• 集群同步:通过 Raft 协议保证集群一致性
• 事件通知:立即通知所有监听者
1.2 心跳健康检查
客户端配置
bash
spring:
cloud:
nacos:
discovery:
# 心跳间隔(默认5秒)
heart-beat-interval: 5000
# 心跳超时(默认15秒)
heart-beat-timeout: 15000
# 实例过期时间(默认30秒)
ip-delete-timeout: 30000
心跳机制:
-
客户端每5秒发送心跳
-
服务端15秒内未收到心跳标记为不健康
-
30秒内未恢复则从注册表中移除
-
客户端层面的保证
2.1 服务发现客户端(NacosNamingService)
bash
public class NacosNamingService implements NamingService {
// 获取服务实例
public List<Instance> selectInstances(String serviceName, boolean healthy) {
// 1. 先检查本地缓存
ServiceInfo serviceInfo = serviceInfoHolder.getServiceInfo(serviceName);
if (serviceInfo == null || isServiceInfoExpired(serviceInfo)) {
// 2. 缓存过期,从服务端获取
serviceInfo = getServiceInfoFromServer(serviceName);
// 更新缓存
serviceInfoHolder.processServiceInfo(serviceInfo);
}
// 3. 过滤健康实例
return serviceInfo.getHosts().stream()
.filter(instance -> healthy ? instance.isHealthy() : true)
.collect(Collectors.toList());
}
}
2.2 客户端缓存策略
bash
// Nacos 客户端缓存管理器
public class ServiceInfoHolder {
// 缓存Map
private final ConcurrentMap<String, ServiceInfo> serviceInfoMap;
// 定时更新任务
private final ScheduledExecutorService updateExecutor;
public void scheduleUpdateIfAbsent(String serviceName) {
// 每10秒更新一次服务列表
updateExecutor.schedule(() -> {
updateServiceInfo(serviceName);
}, 10, TimeUnit.SECONDS);
}
}
3. 实时性保证机制
3.1 Push + Pull 混合模式
bash
// Nacos 客户端订阅机制
public class HostReactor {
// 订阅服务
public void subscribe(String serviceName, EventListener listener) {
// 1. 拉取最新服务列表
ServiceInfo serviceInfo = queryServiceInfo(serviceName);
// 2. 注册 UDP 监听
udpSocket.subscribe(serviceName, listener);
// 3. 启动定时拉取任务
scheduleUpdateTask(serviceName);
}
// UDP 推送处理器
private class PushReceiver implements Runnable {
public void run() {
while (true) {
// 监听 UDP 推送
DatagramPacket packet = udpSocket.receive();
// 解析推送数据
PushPacket pushPacket = parsePacket(packet);
// 更新本地缓存
processPush(pushPacket);
}
}
}
}
混合模式优势:
• Push:服务变化时立即推送(毫秒级)
• Pull:定时拉取作为兜底(10秒间隔)
• 双保险:确保不丢失任何变更
三、配置优化策略
- 客户端配置优化
bash
spring:
cloud:
nacos:
discovery:
server-addr: 127.0.0.1:8848
# 1. 命名空间
namespace: dev
# 2. 集群名称
cluster-name: DEFAULT
# 3. 组名
group: DEFAULT_GROUP
# 4. 元数据
metadata:
version: 1.0
# 5. 权重
weight: 1.0
# 6. 实例类型
ephemeral: true # 临时实例
# 7. 心跳配置
heart-beat-interval: 3000 # 3秒心跳
heart-beat-timeout: 9000 # 9秒超时
ip-delete-timeout: 15000 # 15秒删除
# 8. 重试
retry:
max-retry: 3
# 9. 缓存
cache:
enabled: true
cache-dir: /tmp/nacos/cache
- 服务端配置优化
bash
# Nacos Server 配置文件 nacos/conf/application.properties
# 1. 健康检查
nacos.naming.health.check.enabled=true
# 临时实例检查间隔
nacos.naming.health.check.interval.seconds=3
# 持久实例检查间隔
nacos.naming.health.check.persistent.interval.seconds=30
# 2. 心跳超时
nacos.naming.heart.beat.timeout.seconds=15
# 3. 实例过期
nacos.naming.ip.delete.timeout.seconds=30
# 4. 服务列表缓存
nacos.naming.service.cache.enabled=true
nacos.naming.service.cache.max-size=10000
nacos.naming.service.cache.expire.seconds=10
# 5. 推送配置
nacos.naming.push.enabled=true
nacos.naming.push.thread.pool.size=100
nacos.naming.push.queue.size=10000
nacos.naming.push.max-retry-time=3