Eureka源码之Region、Zone、serviceUrls

一  getServiceUrlsMapFromConfig函数
    public static Map<String, List<String>> getServiceUrlsMapFromConfig(EurekaClientConfig clientConfig, String instanceZone, boolean preferSameZone) {
        Map<String, List<String>> orderedUrls = new LinkedHashMap<>();
        String region = getRegion(clientConfig);
        String[] availZones = clientConfig.getAvailabilityZones(clientConfig.getRegion());
        if (availZones == null || availZones.length == 0) {
            availZones = new String[1];
            availZones[0] = DEFAULT_ZONE;
        }
        logger.debug("The availability zone for the given region {} are {}", region, availZones);
        int myZoneOffset = getZoneOffset(instanceZone, preferSameZone, availZones);

        String zone = availZones[myZoneOffset];
        List<String> serviceUrls = clientConfig.getEurekaServerServiceUrls(zone);
        if (serviceUrls != null) {
            orderedUrls.put(zone, serviceUrls);
        }
        int currentOffset = myZoneOffset == (availZones.length - 1) ? 0 : (myZoneOffset + 1);
        while (currentOffset != myZoneOffset) {
            zone = availZones[currentOffset];
            serviceUrls = clientConfig.getEurekaServerServiceUrls(zone);
            if (serviceUrls != null) {
                orderedUrls.put(zone, serviceUrls);
            }
            if (currentOffset == (availZones.length - 1)) {
                currentOffset = 0;
            } else {
                currentOffset++;
            }
        }

        if (orderedUrls.size() < 1) {
            throw new IllegalArgumentException("DiscoveryClient: invalid serviceUrl specified!");
        }
        return orderedUrls;
    }
二 Region、Zone
上面这个函数,可以发现,客户端依次加载了两个内容,第一个是Region,第二个是Zone,从加载逻辑上我们可以判断他们之间的关系:
1 通过getRegion函数,可以从配置中读取一个Region,所以一个微服务应用只可以属于一个Region。如果不特别配置,默认是default。若我们要自己设置,可以通过eureka.client.region属性来定义。
    public static String getRegion(EurekaClientConfig clientConfig) {
        String region = clientConfig.getRegion();
        if (region == null) {
            region = DEFAULT_REGION;
        }
        region = region.trim().toLowerCase();
        return region;
    }
2 通过getAvailabilityZones函数,可以知道当我们没有特别为Region配置Zone时候,将默认采用defaultZone,这也是配置参数eureka.client.serviceUrl.defaultZone中defaultZone的由来。若要为应用指定Zone,可以通过eureka.client.availability-zones属性来进行设置。从该函数return返回值,可以知道Zone能够设置多个,并且通过逗号分隔配置。由此,我们可以判断Region与Zone是一个对多的关系。
    public String[] getAvailabilityZones(String region) {
        String value = this.availabilityZones.get(region);
        if (value == null) {
            value = DEFAULT_ZONE;
        }
        return value.split(",");
    }
三 serviceUrls
在获取了Region和Zone的信息之后,才开始真正加载Eureka Sever的具体地址,它根据传入的参数根据一定算法确定加载位于哪一个Zone配置的serviceUrls
  int myZoneOffset = getZoneOffset(instanceZone, preferSameZone, availZones);
  String zone = availZones[myZoneOffset];
  List<String> serviceUrls = clientConfig.getEurekaServerServiceUrls(zone);
下面查看getEurekaServerServiceUrls
    public List<String> getEurekaServerServiceUrls(String myZone) {
        String serviceUrls = this.serviceUrl.get(myZone);
        if (serviceUrls == null || serviceUrls.isEmpty()) {
            serviceUrls = this.serviceUrl.get(DEFAULT_ZONE);
        }
        if (!StringUtils.isEmpty(serviceUrls)) {
            final String[] serviceUrlsSplit = StringUtils.commaDelimitedListToStringArray(serviceUrls);
            List<String> eurekaServiceUrls = new ArrayList<>(serviceUrlsSplit.length);
            for (String eurekaServiceUrl : serviceUrlsSplit) {
                if (!endsWithSlash(eurekaServiceUrl)) {
                    eurekaServiceUrl += "/";
                }
                eurekaServiceUrls.add(eurekaServiceUrl);
            }
            return eurekaServiceUrls;
        }

        return new ArrayList<>();
    }
当我们在微服务应用中使用Ribbon来实现服务调用时,对于Zone的设置在负载均衡时实现区域亲和性:Ribbon的默认策略会优先访问处于一个Zone中的服务端实例,只有当同一个Zone中没有可用服务端实例的时候才会访问其他Zone的实例。所以通过Zone属性的定义,配合实际部署物理结构,我们就可以有效设计出对区域性故障的容错集群。

猜你喜欢

转载自blog.csdn.net/chengqiuming/article/details/81044163
今日推荐