写点什么

【Nacos 源码之配置管理 八】客户端怎么获取服务端集群列表

  • 2022 年 10 月 08 日
    江西
  • 本文字数:4189 字

    阅读完需:约 14 分钟

【Nacos源码之配置管理 八】客户端怎么获取服务端集群列表

作者石臻臻,CSDN 博客之星 Top5Kafka Contributornacos Contributor华为云 MVP,腾讯云 TVP,滴滴 Kafka 技术专家 KnowStreaming


KnowStreaming 是滴滴开源的Kafka运维管控平台, 有兴趣一起参与参与开发的同学,但是怕自己能力不够的同学,可以联系我,当你导师带你参与开源!

Part1 前言


在前面第六篇文章中,我们介绍了配置管服务端模块的 ServerListService 类;这个类作用是持有服务端集群列表信息,并且每隔一段时间就会去检查集群中的机器是否正常; ServerListService 类获取集群列表方式是先获取本地文件配置,如果没有配置则检查是否配置了远程服务器配置列表;具体详细可以查看文章 【Nacos源码之配置管理 六】集群模式下服务器之间是如何互相感知的 ;那么客户端如果想要获取配置数据,肯定是需要去服务端获取数据;那么就有以下问题:

  • [x] 客户端如何获取服务端集群列表;

  • [x] 客户端获取数据的时候,去哪一台服务器请求数据

  • [x] 客户端如何保证自己持有的服务端集群列表都是健康的

在客户端 Nacos-client 模块中,也有一个跟 ServerListService 作用类似的类;它是 ServerListManager

Part2ServerListManager


ServerListManager 是一个集群列表管理类,他持有集群列表的信息;1.它可以配置属性 serverAddr 表示集群列表 2.它也可以通过请求获取某个 http 服务的方式动态获取最新的集群列表;并且每 30 秒钟就会去请求一次; 这种方式可以很方便的动态配置集群;例如动态扩容、服务下线等等;

我们看的其中一个构造函数,入参是一个 Properties;Properties 里面可以配置一些属性如:

/**服务器集群列表;用逗号隔开;支持Ip:port或http://,https://+域名的形式**/serverAddr= 127.0.0.1:8848,127.0.0.2:8848,http://serverAddr:80//**命名空间;可以支持多环境隔离,nacos-config默认内置一个空字符的命名空间**/namespace=dev/**除了serverAddr中可以自定义配置集群列表;Nacos也支持动态获取集群列表   更详细的介绍请看 https://nacos.io/zh-cn/docs/namespace-endpoint-best-practices.html 。**/endpoint=/**端口 默认8080**/endpointPort=/**是否解析endpoint规则;默认为true;**/isUseEndpointParsingRule=true/**上下文路径;默认为nacos**/contextPath=nacosconfigRetryTime=/**最大重试次数默认3次**/maxRetry=enableRemoteSyncConfig=

复制代码

等等其他一些属性; 构造函数就是获取这些属性并初始化

 public ServerListManager(Properties properties) throws NacosException {        isStarted = false;        serverAddrsStr = properties.getProperty(PropertyKeyConst.SERVER_ADDR);        String namespace = properties.getProperty(PropertyKeyConst.NAMESPACE);        initParam(properties);        if (StringUtils.isNotEmpty(serverAddrsStr)) {            isFixed = true;            List<String> serverAddrs = new ArrayList<String>();            String[] serverAddrsArr = serverAddrsStr.split(",");            for (String serverAddr: serverAddrsArr) {                if (serverAddr.startsWith(HTTPS) || serverAddr.startsWith(HTTP)) {                    serverAddrs.add(serverAddr);                } else {                    String[] serverAddrArr = serverAddr.split(":");                    if (serverAddrArr.length == 1) {                        serverAddrs.add(HTTP + serverAddrArr[0] + ":" + ParamUtil.getDefaultServerPort());                    } else {                        serverAddrs.add(HTTP + serverAddr);                    }                }            }            serverUrls = serverAddrs;            if (StringUtils.isBlank(namespace)) {                name = FIXED_NAME + "-" + getFixedNameSuffix(serverUrls.toArray(new String[serverUrls.size()]));            } else {                this.namespace = namespace;                this.tenant = namespace;                name = FIXED_NAME + "-" + getFixedNameSuffix(serverUrls.toArray(new String[serverUrls.size()])) + "-"                    + namespace;            }        } else {            if (StringUtils.isBlank(endpoint)) {                throw new NacosException(NacosException.CLIENT_INVALID_PARAM, "endpoint is blank");            }            isFixed = false;            if (StringUtils.isBlank(namespace)) {                name = endpoint;                addressServerUrl = String.format("http://%s:%d/%s/%s", endpoint, endpointPort, contentPath,                    serverListName);            } else {                this.namespace = namespace;                this.tenant = namespace;                name = endpoint + "-" + namespace;                addressServerUrl = String.format("http://%s:%d/%s/%s?namespace=%s", endpoint, endpointPort,                    contentPath, serverListName, namespace);            }        }
    }
复制代码
  1. 获取并解析 endpoint; 为了让客户端可能敏锐的感知到服务端集群的变化(扩容、下线),利用本地配置文件 Properties 获取的话需要重启服务器不够友好 ,所以我们可以通过一个专门的服务来提供集群列表的数据;这个就是 endpoint.客户端定时的去请求这个 endpoint 获取最新的集群列表; 这个 endpoint 怎么配置呢?它解析过程比较复杂;看下面图


  1. 如果配置了属性 serverAddr; 那么 endpoint 就不会生效;客户端会优先读取 serverAddr 的集群列表;(有没有觉得跟服务端获取集群列表很相似?) 客户端将 serverAddr 解析成多个服务器地址;并放入列表属性 serverUrls 中;并且属性 isFixed=true;表示集群列表是固定的

  2. 如果没有配置属性 serverAddr,则会从获取 endpoint;注意:serverAddr 和 endpoint 必须配置一个; 最终组装成一个服务器地址 addressServerUrl 是http://{endpoint}:{endpointPort}/{contentPath}/serverListName ; serverListName 默认是serverlist;但是 serverListName 暂时不可以通过 Properties 配置; 属性isFixed=false;表示不是固定的集群列表;后续还是需要去访问 addressServerUrl 获取集群列表的

PS:看到这个 addressServerUrl 地址,有没有似曾相识的感觉?对~没错 ~!我们再介绍服务端获取集群列表的时候介绍过,它也有两种方式;一种是从 cluster.conf 中读取;还有一种是从一个 url 中请求 http 获取; 那个地址跟这里的地址一样;这样做是合理的;因为要保证服务端和客户端获取到的集群列表都应该是一致的; 【Nacos源码之配置管理 六】集群模式下服务器之间是如何互相感知的

1start 方法


通过上面的构造函数我们知道; 客户端有两种方式获取集群列表;

  1. 一种是 通过 Properties 中的属性 serverAddr 配置;

  2. 一种是通过 Properties 中配置属性 endpoint;最终组装成一个服务器地址 addressServerUrl 是http://{endpoint}:{endpointPort}/{contentPath}/serverListName ;

如果是上面的第 2 中方式,只是组装了一个地址而已,那么什么时候去通过这个地址拿集群列表呢?这个获取触发的方法就是 start()方法

通过方法我们可以知道只有是第 2 中方式的时候才会执行这里面的逻辑;(isFixed=false;)

  1. GetServerListTask 是获取集群列表的任务;具体流程是:①.请求 addressServerUrl 获取列表;②.如果集群有变化;则更新列表 serverUrls③.如果集群有变化,更新属性 currentServerAddr,这个表示当前客户端需要连接的服务端集群中的某个服务; 具体操作是创建一个随机遍历器 iterator;然后currentServerAddr = iterator.next();

  2. 如果 GetServerListTask 一直获取不到集群列表;则最大会重试 5 次;如果还是查询不到则会抛异常

  3. 每 30 秒执行一次 GetServerListTask 任务;

流程是这样的


客户端如何获取服务端集群列表;


分析完上面 ServerListManager 之后,这个问题也就很明了了;

  1. 本地配置文件获取

  2. 远程 http 服务获取

Part3ServerHttpAgent


ServerHttpAgent 是一个 Http 代理类; 做一些鉴权相关的事情;它持有一个 ServerListManager 属性;它负责请求哪台服务器,已经请求失败重试、更换服务器地址等操作;

2 客户端获取数据的时候,去哪一台服务器请求数据


我们在分析源码的时候,上面有设置一个currentServerAddr的属性; 这个属性就是客户端发起请求时候的服务器地址;这个属性可以看成是 将多个服务器地址 随机打乱之后排好序; 然后遍历这个列表;配置文件 Properties 中有一个 maxRetry 属性,表示每个服务器最大重试次数,默认 3 次; 如果每个服务地址都重试了 3 次之后就会抛出异常客户端发起请求的整个流程是这样的:

  1. 对当前的 currentServerAddr 发起请求,如果成功,currentServerAddr 不变,然后返回结果;

  2. 如果请求失败,则会获取下一个服务器地址serverListMgr.getIterator().next();

  3. 重复 2,并且仍然失败,则重新打乱 serverUrls 之后再来一次重新遍历;

  4. 如果 3 打乱了 maxRetry 次之后,则不再继续,抛出异常

  5. 如果以上有请求成功,则把请求成功的地址改成 currentServerAddr

总结一句话就是: 轮流请求服务器地址直到成功或者超过重试次数或者超过超时时间

3 客户端如何保证自己持有的服务端集群列表都是健康的


客户端不能保证服务端列表都是健康的; 他在对服务端发起请求的时候如果请求失败会主动换其他的服务端地址;

发布于: 刚刚阅读数: 4
用户头像

关注公众号: 石臻臻的杂货铺 获取最新文章 2019.09.06 加入

进高质量滴滴技术交流群,只交流技术不闲聊 加 szzdzhp001 进群 20w字《Kafka运维与实战宝典》PDF下载请关注公众号:石臻臻的杂货铺

评论

发布
暂无评论
【Nacos源码之配置管理 八】客户端怎么获取服务端集群列表_nacos_石臻臻的杂货铺_InfoQ写作社区