6 nacos注册中心之服务地址的查询

举报
周杰伦本人 发表于 2022/05/13 21:26:42 2022/05/13
【摘要】 6 nacos注册中心之服务地址的查询 InstanceController的list()方法 doSrvIPXT()方法 总结 6 nacos注册中心之服务地址的查询nacos的服务端给我们提供了获取注册中心中服务地址的查询api,对应的Open API如下:发送get请求http://127.0.0.1:848/nacos/v1/ns/instance/list?serviceName...

6 nacos注册中心之服务地址的查询

nacos的服务端给我们提供了获取注册中心中服务地址的查询api,对应的Open API如下:

发送get请求

http://127.0.0.1:848/nacos/v1/ns/instance/list?serviceName=example

下载nacos服务端的源码,我们找到InstanceController类,有关实例的接口都在这个类中,我们从调用的api找到对应的Controller层

查询服务地址的方法是对应InstanceController的list方法:

InstanceController的list()方法

@GetMapping("/list")
public JSONObject list(HttpServletRequest request) throws Exception {

    String namespaceId = WebUtils.optional(request, CommonParams.NAMESPACE_ID,
        Constants.DEFAULT_NAMESPACE_ID);

    String serviceName = WebUtils.required(request, CommonParams.SERVICE_NAME);
    String agent = WebUtils.getUserAgent(request);
    String clusters = WebUtils.optional(request, "clusters", StringUtils.EMPTY);
    String clientIP = WebUtils.optional(request, "clientIP", StringUtils.EMPTY);
    Integer udpPort = Integer.parseInt(WebUtils.optional(request, "udpPort", "0"));
    String env = WebUtils.optional(request, "env", StringUtils.EMPTY);
    boolean isCheck = Boolean.parseBoolean(WebUtils.optional(request, "isCheck", "false"));

    String app = WebUtils.optional(request, "app", StringUtils.EMPTY);

    String tenant = WebUtils.optional(request, "tid", StringUtils.EMPTY);

    boolean healthyOnly = Boolean.parseBoolean(WebUtils.optional(request, "healthyOnly", "false"));

    return doSrvIPXT(namespaceId, serviceName, agent, clusters, clientIP, udpPort, env, isCheck, app, tenant,
        healthyOnly);
}
  1. 解析请求参数,包括namespaceId、服务名、代理、集群、客户端ip等等信息
  2. 通过doSrvIPXT()方法返回服务列表数据

我们看一下doSrvIPXT()方法中做了什么

doSrvIPXT()方法

doSrvIPXT()方法的主要功能是获取服务信息和所有的节点内容

public JSONObject doSrvIPXT(String namespaceId, String serviceName, String agent, String clusters, String clientIP,
                            int udpPort,
                            String env, boolean isCheck, String app, String tid, boolean healthyOnly)
    throws Exception {

    ClientInfo clientInfo = new ClientInfo(agent);
    JSONObject result = new JSONObject();
    Service service = serviceManager.getService(namespaceId, serviceName);

    if (service == null) {
        if (Loggers.SRV_LOG.isDebugEnabled()) {
            Loggers.SRV_LOG.debug("no instance to serve for service: {}", serviceName);
        }
        result.put("name", serviceName);
        result.put("clusters", clusters);
        result.put("hosts", new JSONArray());
        return result;
    }

    checkIfDisabled(service);

    long cacheMillis = switchDomain.getDefaultCacheMillis();

    // now try to enable the push
    try {
        if (udpPort > 0 && pushService.canEnablePush(agent)) {
            pushService.addClient(namespaceId, serviceName,
                clusters,
                agent,
                new InetSocketAddress(clientIP, udpPort),
                pushDataSource,
                tid,
                app);
            cacheMillis = switchDomain.getPushCacheMillis(serviceName);
        }
    } catch (Exception e) {
        Loggers.SRV_LOG.error("[NACOS-API] failed to added push client", e);
        cacheMillis = switchDomain.getDefaultCacheMillis();
    }

    List<Instance> srvedIPs;

    srvedIPs = service.srvIPs(Arrays.asList(StringUtils.split(clusters, ",")));

    // filter ips using selector:
    if (service.getSelector() != null && StringUtils.isNotBlank(clientIP)) {
        srvedIPs = service.getSelector().select(clientIP, srvedIPs);
    }

    if (CollectionUtils.isEmpty(srvedIPs)) {

        if (Loggers.SRV_LOG.isDebugEnabled()) {
            Loggers.SRV_LOG.debug("no instance to serve for service: {}", serviceName);
        }

        if (clientInfo.type == ClientInfo.ClientType.JAVA &&
            clientInfo.version.compareTo(VersionUtil.parseVersion("1.0.0")) >= 0) {
            result.put("dom", serviceName);
        } else {
            result.put("dom", NamingUtils.getServiceName(serviceName));
        }

        result.put("hosts", new JSONArray());
        result.put("name", serviceName);
        result.put("cacheMillis", cacheMillis);
        result.put("lastRefTime", System.currentTimeMillis());
        result.put("checksum", service.getChecksum());
        result.put("useSpecifiedURL", false);
        result.put("clusters", clusters);
        result.put("env", env);
        result.put("metadata", service.getMetadata());
        return result;
    }

    Map<Boolean, List<Instance>> ipMap = new HashMap<>(2);
    ipMap.put(Boolean.TRUE, new ArrayList<>());
    ipMap.put(Boolean.FALSE, new ArrayList<>());

    for (Instance ip : srvedIPs) {
        ipMap.get(ip.isHealthy()).add(ip);
    }

    if (isCheck) {
        result.put("reachProtectThreshold", false);
    }

    double threshold = service.getProtectThreshold();

    if ((float) ipMap.get(Boolean.TRUE).size() / srvedIPs.size() <= threshold) {

        Loggers.SRV_LOG.warn("protect threshold reached, return all ips, service: {}", serviceName);
        if (isCheck) {
            result.put("reachProtectThreshold", true);
        }

        ipMap.get(Boolean.TRUE).addAll(ipMap.get(Boolean.FALSE));
        ipMap.get(Boolean.FALSE).clear();
    }

    if (isCheck) {
        result.put("protectThreshold", service.getProtectThreshold());
        result.put("reachLocalSiteCallThreshold", false);

        return new JSONObject();
    }

    JSONArray hosts = new JSONArray();

    for (Map.Entry<Boolean, List<Instance>> entry : ipMap.entrySet()) {
        List<Instance> ips = entry.getValue();

        if (healthyOnly && !entry.getKey()) {
            continue;
        }

        for (Instance instance : ips) {

            // remove disabled instance:
            if (!instance.isEnabled()) {
                continue;
            }

            JSONObject ipObj = new JSONObject();

            ipObj.put("ip", instance.getIp());
            ipObj.put("port", instance.getPort());
            // deprecated since nacos 1.0.0:
            ipObj.put("valid", entry.getKey());
            ipObj.put("healthy", entry.getKey());
            ipObj.put("marked", instance.isMarked());
            ipObj.put("instanceId", instance.getInstanceId());
            ipObj.put("metadata", instance.getMetadata());
            ipObj.put("enabled", instance.isEnabled());
            ipObj.put("weight", instance.getWeight());
            ipObj.put("clusterName", instance.getClusterName());
            if (clientInfo.type == ClientInfo.ClientType.JAVA &&
                clientInfo.version.compareTo(VersionUtil.parseVersion("1.0.0")) >= 0) {
                ipObj.put("serviceName", instance.getServiceName());
            } else {
                ipObj.put("serviceName", NamingUtils.getServiceName(instance.getServiceName()));
            }

            ipObj.put("ephemeral", instance.isEphemeral());
            hosts.add(ipObj);

        }
    }

    result.put("hosts", hosts);
    if (clientInfo.type == ClientInfo.ClientType.JAVA &&
        clientInfo.version.compareTo(VersionUtil.parseVersion("1.0.0")) >= 0) {
        result.put("dom", serviceName);
    } else {
        result.put("dom", NamingUtils.getServiceName(serviceName));
    }
    result.put("name", serviceName);
    result.put("cacheMillis", cacheMillis);
    result.put("lastRefTime", System.currentTimeMillis());
    result.put("checksum", service.getChecksum());
    result.put("useSpecifiedURL", false);
    result.put("clusters", clusters);
    result.put("env", env);
    result.put("metadata", service.getMetadata());
    return result;
}

代码虽然有点长,但内容非常好理解,主要做三件事:

  1. 调用serviceManager.getService()方法根据传入的namespaceId serviceName获得Service实例,如果获得的实例为空,就打印没有相关实例的日志,并返回结果,如果Service实例不为空,执行下面的逻辑
  2. 检查Service是否禁用
  3. 试着开启推送,添加推送的客户端
  4. 从Service实例中调用srvIPs方法得到所有服务提供者的实例信息。
  5. 使用过滤器来获取到的实例信息
  6. 遍历组装JSON字符串并返回。

总结

这就是nacos的服务查询功能呢,对应接口就是这个

get请求

http://127.0.0.1:848/nacos/v1/ns/instance/list?serviceName=example

整体逻辑
深入源码,了解它的本质,它的实现也比较好理解,和我们经常开发的Controller等业务服务差不多,核心代码就是通过srvIPs()方法来获取实例列表,然后封装成JSON,返回给客户端,让我们一起学习,一起进步,一起了解nacos源码

【版权声明】本文为华为云社区用户原创内容,转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息, 否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。