nacos1.4.2
一、注册表结构
// com.alibaba.nacos.naming.core.ServiceManager
/**
* Map(namespace, Map(group::serviceName, Service)).
*/
private final Map<String, Map<String, Service>> serviceMap = new ConcurrentHashMap<>();
nacos1.X的注册表存于ServiceManager的一个ConcurrentHashMap中,key为命名空间,值又是一个ConcurrentHashMap,内层的ConcurrentHashMapkey为组名+服务名。值为Service服务对象。
这个Service内部又存放了一个hashMap,key为集群名,值为集群对象Cluster。Cluster内部存放两个Set集合,一个存放持久化实例,一个存放临时实例。
// com.alibaba.nacos.naming.core.Service
// 这就是serve内部具体存放集群信息位置
private Map<String, Cluster> clusterMap = new HashMap<>();
// com.alibaba.nacos.naming.core.Cluster
// 持久化实例集合
@JsonIgnore
private Set<Instance> persistentInstances = new HashSet<>();
// 临时实例集合
@JsonIgnore
private Set<Instance> ephemeralInstances = new HashSet<>();
实例里面存放了IP、端口、集群名称等信息。
public Instance(String ip, int port) {
this.setIp(ip);
this.setPort(port);
this.setClusterName(UtilsAndCommons.DEFAULT_CLUSTER_NAME);
}
public Instance(String ip, int port, String clusterName) {
this.setIp(ip.trim());
this.setPort(port);
this.setClusterName(clusterName);
}
public Instance(String ip, int port, String clusterName, String tenant, String app) {
this.setIp(ip.trim());
this.setPort(port);
this.setClusterName(clusterName);
this.tenant = tenant;
this.app = app;
}
以上所有结构组成了nacos1.X的实例注册表。
二、客户端服务注册核心源码
客户端注册实例主要做两件事情,定时发送服务健康状态心跳、发送服务注册请求。
// 在服务启动的时候调用 注册实例
public void registerInstance(String serviceName, String groupName, Instance instance) throws NacosException {
NamingUtils.checkInstanceIsLegal(instance);
String groupedServiceName = NamingUtils.getGroupedName(serviceName, groupName);
// 如果是临时实例就服务端发心跳,内部是每隔5秒循环调用
if (instance.isEphemeral()) {
BeatInfo beatInfo = this.beatReactor.buildBeatInfo(groupedServiceName, instance);
this.beatReactor.addBeatInfo(groupedServiceName, beatInfo);
}
// 注册实例
this.serverProxy.registerService(groupedServiceName, groupName, instance);
}
定时发送服务健康状态心跳
如果注册实例是临时实例,则建立心跳机制,原理是发起一个延时5秒的的异步任务向服务端发送健康状态,在这个任务的末尾又调用本身,实现每隔5秒的循环调用,发送心跳。
发送服务注册请求
三、服务端服务注册核心源码
服务端是一个restful风格的HTTP接口
这个接口内会做以下几步;
1. 如果service是第一次创建,则在初始化时创建一个针对该service 的健康检查定时任务,延迟5秒并且每隔5秒执行一次。这个定时任务遍历service下的所有实例,如果发现服务端超过15秒没收到客户端的心跳,则将该实例健康状态标记为false,如果超过30秒没发送心跳过来,则将该实例从注册中心剔除。
2. 将注册的实例信息放到一个ArrayBlockingQueue阻塞队列中,等待消费。所以这里是一个异常操作。
这个队列的消费逻辑是在nacos启动时开启了一个死循环。
在实际的消费注册服务操作时,用到了写时复制的设计避免读写冲突。
实例权重范围是0.01-10000。