源码地址: git clone https://gitee.com/mirrors/Nacos.git
启动问题1.找不到类 在ideal控制台使用:mvn compile 启动问题2.服务找不到(nacos默认使用集群形式) -Dnacos.standalone=true
进行服务注册
NamingProxy 366行 使用了故障转移的算法 大致思路:如果有5个注册中心,那么会随机取一个服务请求注册如果注册成功直接返回,如果注册失败就会尝试下一个,如果所有的都注册失败则直接抛出异常 疑问:只在一个上注册,那么其他服务是怎么知道到这个服务注册的呢? 猜测应该是用了定时任务拉取后做的同步数据
public String reqAPI(String api, Mapparams, List servers, String method) { params.put("namespaceId", this.getNamespaceId()); if (CollectionUtils.isEmpty(servers) && StringUtils.isEmpty(this.nacosDomain)) { throw new IllegalArgumentException("no server available"); } else { Exception exception = new Exception(); if (servers != null && !servers.isEmpty()) { Random random = new Random(System.currentTimeMillis());//根据当前时间创建随机数 int index = random.nextInt(servers.size());//根据服务数量获取随机数 for(int i = 0; i < servers.size(); ++i) { String server = (String)servers.get(index);//获取随机的注册地址 try { return this.callServer(api, params, server, method);//调用nacos注册中心 } catch (NacosException var11) { exception = var11; LogUtils.NAMING_LOGGER.error("request {} failed.", server, var11); } catch (Exception var12) { exception = var12; LogUtils.NAMING_LOGGER.error("request {} failed.", server, var12); } index = (index + 1) % servers.size();//出现异常请求下一个 } throw new IllegalStateException("failed to req API:" + api + " after all servers(" + servers + ") tried: " + ((Exception)exception).getMessage()); } else { int i = 0; while(i < 3) { try { return this.callServer(api, params, this.nacosDomain); } catch (Exception var13) { exception = var13; LogUtils.NAMING_LOGGER.error("[NA] req api:" + api + " failed, server(" + this.nacosDomain, var13); ++i; } } throw new IllegalStateException("failed to req API:/api/" + api + " after all servers(" + servers + ") tried: " + ((Exception)exception).getMessage()); } } }
通过httpclient发送请求到/nacos/v1/ns/instance
public String callServer(String api, Mapparams, String curServer, String method) throws NacosException { long start = System.currentTimeMillis(); long end = 0L; this.checkSignature(params); List headers = this.builderHeaders(); String url;//请求路径为:/nacos/v1/ns/instance if (!curServer.startsWith("https://") && !curServer.startsWith("http://")) { if (!curServer.contains(":")) { curServer = curServer + ":" + this.serverPort; } url = HttpClient.getPrefix() + curServer + api; } else { url = curServer + api; } HttpResult result = HttpClient.request(url, headers, params, "UTF-8", method); end = System.currentTimeMillis(); MetricsMonitor.getNamingRequestMonitor(method, url, String.valueOf(result.code)).observe((double)(end - start)); if (200 == result.code) { return result.content; } else if (304 == result.code) { return ""; } else { throw new NacosException(500, "failed to req API:" + curServer + api + ". code:" + result.code + " msg: " + result.content); } }
Nacos Server端
请求到服务端/nacos/v1/ns/instance地址--》InstanceController
@CanDistro
@PostMapping
@Secured(parser = NamingResourceParser.class, action = ActionTypes.WRITE)
public String register(HttpServletRequest request) throws Exception {
final String namespaceId = WebUtils//根据namespaceId获取命名空间,如果没有则为默认public
.optional(request, CommonParams.NAMESPACE_ID, Constants.DEFAULT_NAMESPACE_ID);
final String serviceName = WebUtils.required(request, CommonParams.SERVICE_NAME);//根据serviceName获取服务名
NamingUtils.checkServiceNameFormat(serviceName);//服务名格式为DEFAULT_GROUP@@nacos-test
final Instance instance = HttpRequestInstanceBuilder.newBuilder()//根据当前请求创建临时实例
.setDefaultInstanceEphemeral(switchDomain.isDefaultInstanceEphemeral()).setRequest(request).build();
getInstanceOperator().registerInstance(namespaceId, serviceName, instance);//注册实例
return "ok";
}
/这里是客户端请求会进入InstanceOperatorClientImpl
boolean ephemeral = instance.isEphemeral();//判断是否是临时实例
String clientId = IpPortbasedClient.getClientId(instance.toInetAddr(), ephemeral);//根据ip获取clientId——》127.0.0.1:8181#true
createIpPortClientIfAbsent(clientId);//如果容器已有当前ip实例建立连接
Service service = getService(namespaceId, serviceName, ephemeral);//创建服务实例
clientOperationService.registerInstance(service, instance, clientId);//注册客户端实例
@Override
public void registerInstance(Service service, Instance instance, String clientId) {
Service singleton = ServiceManager.getInstance().getSingleton(service);//获取服务单实例
Client client = clientManager.getClient(clientId);
if (!clientIsLegal(client, clientId)) {//判断连接是否已经断开或者不是临时连接
return;
}
InstancePublishInfo instanceInfo = getPublishInfo(instance);//创建事件实例
client.addServiceInstance(singleton, instanceInfo);
client.setLastUpdatedTime();
NotifyCenter.publishEvent(new ClientOperationEvent.ClientRegisterServiceEvent(singleton, clientId));
NotifyCenter
.publishEvent(new metadataEvent.InstancemetadataEvent(singleton, instanceInfo.getmetadataId(), false));//发布事件
}



