服务下线机制及源码剖析
服务下线的接口为 /nacos/v1/ns/instance,跟注册是一个接口,但是HTTP的谓词为:DELETE,调用这个接口的逻辑大致为:先从注册表中根据namespaceId和serviceName获取到相应的Instances的副本,然后从副本中把需要下线的instance删除,再把这个处理后的Instances副本去替换注册表中相应的信息,源码中前半段逻辑,就是得出一个删除完实例的Instances副本,后边的逻辑其实跟注册逻辑一致,源码如下:
// com.alibaba.nacos.naming.controllers.InstanceController#deregister
@CanDistro
@DeleteMapping
@Secured(parser = NamingResourceParser.class, action = ActionTypes.WRITE)
public String deregister(HttpServletRequest request) throws Exception {
// 获取HTTP请求传过来需要注销的intance
Instance instance = getIpAddress(request);
String namespaceId = WebUtils.optional(request, CommonParams.NAMESPACE_ID, Constants.DEFAULT_NAMESPACE_ID);
String serviceName = WebUtils.required(request, CommonParams.SERVICE_NAME);
NamingUtils.checkServiceNameFormat(serviceName);
// 根据namespaceId和serviceName获取对应的service
Service service = serviceManager.getService(namespaceId, serviceName);
if (service == null) {
Loggers.SRV_LOG.warn("remove instance from non-exist service: {}", serviceName);
return "ok";
}
// 调用删除Instance的service方法
serviceManager.removeInstance(namespaceId, serviceName, instance.isEphemeral(), instance);
return "ok";
}
// com.alibaba.nacos.naming.core.ServiceManager#removeInstance
public void removeInstance(String namespaceId, String serviceName, boolean ephemeral, Instance... ips)
throws NacosException {
Service service = getService(namespaceId, serviceName);
// 加锁控制并发操作
synchronized (service) {
removeInstance(namespaceId, serviceName, ephemeral, service, ips);
}
}
// com.alibaba.nacos.naming.core.ServiceManager#removeInstance
private void removeInstance(String namespaceId, String serviceName, boolean ephemeral, Service service,
Instance... ips) throws NacosException {
String key = KeyBuilder.buildInstanceListKey(namespaceId, serviceName, ephemeral);
// 从注册表中把需要删除的实例ips进行移除,并返回一个已经移除后的Instance List
List<Instance> instanceList = substractIpAddresses(service, ephemeral, ips);
Instances instances = new Instances();
instances.setInstanceList(instanceList);
// 执行真正的删除Instance的逻辑,这里执行的逻辑跟注册Instance是一样的逻辑
// 就是把传入的instances,去更新注册表中的数据
consistencyService.put(key, instances);
}