Eureka高可用注册中心通过defaultZone深入理解zone和serviceUrl

先上配置文件了,刚开始是直接指定两个配置中心地址,发现两个中心要按一定顺序放,这就有点坑了,我们根本不知道哪个先放前面,尝试几次只有最后一个服务注册中心有交,然后就想到改变一种方法实现

eureka:
  client:
    prefer-same-zone-eureka: true
    registerWithEureka: true
    fetch-registry: true
  # 假设指定region为上海
    region: sh
    availability-zones:
   #假设上海下面有两个region
      sh: pudong,xuhui
    serviceUrl:
#      defaultZone: http://user:password@192.168.11.45:8761/eureka/
      pudong: http://user:password@192.168.11.45:8761/eureka/
      xuhui: http://user:password@192.168.11.46:8761/eureka/
  instance:
    prefer-ip-address: true     #在eureka里显示IP,下一行是显示地址信息的格式
    instance-id: ${spring.application.name}:${spring.cloud.client.ipAddress}:${spring.application.instance_id:${server.port}}
    ip-address: 192.168.11.126
    secure-port: 5888
    metadata-map:
      zone: xuhui

serviceUrl是真正的属性,service-url的配置内容是map,map的内容是可以自己发挥的,只要是key: value格式就行(注意有个空格)。有很多map类型的配置,比如availabilityZones,metadata-map都是的,内容虽然是key: value格式,但是都是可以自由发挥。其中metadata-map比较特殊,里面有个zone的属性,会被eureka client解析,当成客户端默认指向的zone来处理。

注册中心选择逻辑
1. 如果prefer-same-zone-eureka为false,按照service-url下的 list取第一个注册中心来注册,并和其维持心跳检测。不会再向list内的其它的注册中心注册和维持心跳。只有在第一个注册失败的情况下,才会依次向其它的注册中心注册,总共重试3次,如果3个service-url都没有注册成功,则注册失败。每隔一个心跳时间,会再次尝试。
2. 如果prefer-same-zone-eureka为true,先通过region取availability-zones内的第一个zone,然后通过这个zone取service-url下的list,并向list内的第一个注册中心进行注册和维持心跳,不会再向list内的其它的注册中心注册和维持心跳。只有在第一个注册失败的情况下,才会依次向其它的注册中心注册,总共重试3次,如果3个service-url都没有注册成功,则注册失败。每隔一个心跳时间,会再次尝试。

所以说,为了保证服务注册到同一个zone的注册中心,一定要注意availability-zones的顺序,必须把同一zone写在前面

2. 服务调用的配置文件

eureka:
  instance:
    metadata-map:
      zone: pudong

服务消费者和服务提供者分别属于哪个zone,均是通过eureka.instance.metadata-map.zone来判定的。
服务消费者会先通过ribbon去注册中心拉取一份服务提供者的列表,然后通过eureka.instance.metadata-map.zone指定的zone进行过滤,过滤之后如果同一个zone内的服务提供者有多个实例,则会轮流调用。
只有在同一个zone内的所有服务提供者都不可用时,才会调用其它zone内的服务提供者。

 

再看源码 getAvailabilityZones()和getEurekaServerServiceUrls()两个方法的实现。现在向两个服务注册中心添加地址的时候,为什么不能用空格了吧,并且其它符号更不行,

// 根据region,从availabilityZones这个Map中获取key值对应的配置。
// availabilityZones是通过eureka.client.availability-zones配置的,
 
// 可以配置多个availabilityZones,key表示region,value表region对应的zones
// 假设有多个zones,用逗号隔开。
// region通过eureka.client.region来设置,假设不设置,默认为"us-east-1c"。
public String[] getAvailabilityZones(String region) {
    String value = (String)this.availabilityZones.get(region);
    if (value == null) {
        value = "defaultZone";
    }
 
    return value.split(",");
}
 
// 根据zone来获取serviceUrls,假设用逗号隔开会拆分成数组。
public List<String> getEurekaServerServiceUrls(String myZone) {
    String serviceUrls = (String)this.serviceUrl.get(myZone);
    if (serviceUrls == null || serviceUrls.isEmpty()) {
        serviceUrls = (String)this.serviceUrl.get("defaultZone");
    }
 
    if (!StringUtils.isEmpty(serviceUrls)) {
        String[] serviceUrlsSplit = StringUtils.commaDelimitedListToStringArray(serviceUrls);
        List<String> eurekaServiceUrls = new ArrayList(serviceUrlsSplit.length);
        String[] var5 = serviceUrlsSplit;
        int var6 = serviceUrlsSplit.length;
 
        for(int var7 = 0; var7 < var6; ++var7) {
            String eurekaServiceUrl = var5[var7];
            if (!this.endsWithSlash(eurekaServiceUrl)) {
                eurekaServiceUrl = eurekaServiceUrl + "/";
            }
 
            eurekaServiceUrls.add(eurekaServiceUrl.trim());
        }
 
        return eurekaServiceUrls;
    } else {
        return new ArrayList();
    }
}

下面这一行配置要注意注册中心的顺序, 否则只有一例生效或者报错,原因就是后面的循环拿值没对应上,分析如下:

    serviceUrl:
      defaultZone: http://user:pass@192.168.11.46:8761/eureka/,http://user:pass@192.168.11.45:8761/eureka/ 

Eureka会先获取region,如果我们没有设置region,region默认值为"us-east-1c",然后会根据这个region去获取对应的availabilityZones。

然后循环availabilityZones的值,使用每个zone来调用getEurekaServerServiceUrls,获取serviceUrl,最终形成一个zone为key,serviceUrls(因为可能一个zone有多个serviceUrl)列表为value的map。

在使用serviceUrl的时候,使用两重循环:

会按照顺序,逐个取availabilityZones的zone,从map中获取serviceUrls,在逐个循环serviceUrls,来判断是否可达,如果任意serviceUrl可达则停止,否则一致尝试到最后。

如果availabilityZones为空,或者根据它的值取不到serviceUrls,则会返回key为defaultZone的serviceUrls。如果我们也指定了defaultZone对应的serviceUrls,会覆盖原来的defaultZone,否则使用默认的http:// localhost:8761/eureka。
 

如果想用自己的zone,该如何设置。
首先要设置region,不设置也可以,不设置就按照"us-east-lc"来组织后面的设置。并且根据region一定要能获取availabilityZones的zone值,如果没有就会默认使用defaultZone。我们假设自己设置region为china。然后需要设值availabilityZones,假设有两个sh:pudong,xuhui。然后在serviceUrls中设置pudong: xxxx 换行xuhui: xxxx,分别指向两个服务,

坑:注意getAvailabilityZones这个方法不会trim(),所以逗号后面不要有空格,不然用带空格的key会找不到serviceUrl,这个实现实在有点掉价。而getEurekaServerServiceUrls方法是加了trim()方法的 ,逗号后面可以有空格。


然后启动之后就会把服务注册到两个服务中心,互不影响的两个服务中心,当然如果是集成高可用的服务注册中心,注册中心又是互相注册同步过,那么服务只需要注册任意一个中心,两个服务中心都是可以看到这个服务的。

配置这种事情,简单也可以用,复杂点也能很好发挥作用。有时间就应该慢慢深入研究。

©️2020 CSDN 皮肤主题: 大白 设计师:CSDN官方博客 返回首页