11.ribbon区域亲和

一、简介

ribbon的区域亲和机制如下(需要说明一点,亲和性发生在过滤阶段,请参考负载均衡器中server列表是如何动态更新的部分):
在这里插入图片描述
以上的图示及文字仅为举例说明,下面描述一下图上表示的流程:

首先,先看右下角的provider集群,因为会分别部署在北京,上海,广州三个地区,把这里地区看作zone,故有三个zone。

provider集群会把实例信息(ip+port+name等等)按照配置eureka.client.serviceUrl.defaultZone,遍历配置的eureka实例,注册到Eureka集群。

其次,Eureka集群每个实例都会具有provider的实例信息。

因为eureka实例也会根据eureka.client.serviceUrl.defaultZone,遍历配置的eureka实例,把provider实例信息进行复制(但仅传播一级,不会多级传播)。

最后,Consumer从Eureka集群获取到服务实例的列表,然后根据zone(Consumer使用的zone来自于自己的配置文件:eureka.instance.metadataMap.zone)进行比对,即亲和。

二、实现

请参考ServerListFilter的ZonePreferenceServerListFilter

三、问题&测试

  1. 如果provider有多个zone,但是consumer亲和性选择的zone的server整个不可用,会不会导致Consumer没有可用的provider?

    参考ServerListFilte中的ZoneAffinityServerListFilter:

    1. 其首先进行亲和性过滤,即过滤后剩下的server都是同一个zone的
    2. 之后对这些server进行健康检查,如果认为不健康,则返回之前所有的server列表,否则,使用亲和性server。

    再参考ZonePreferenceServerListFilter,这里,我们假设consumer已经正确配置了自己需要的zone,比如eureka.instance.metadataMap.zone=北京

    注意:如果consumer配置文件没有设置zone,则zone为defaultZone,而provider设置了正确的zone,由于zone不相同,那么将不涉及亲和性问题。那么,在负载均衡阶段,将使用ZoneAwareLoadBalancer来过滤不健康的zone,之后轮询选择。

    1. 参考ZonePreferenceServerListFilter的如下代码:

      public List<Server> getFilteredListOfServers(List<Server> servers) {
          List<Server> output = super.getFilteredListOfServers(servers);
          if (this.zone != null && output.size() == servers.size()) {
              List<Server> local = new ArrayList<Server>();
              for (Server server : output) {
                  if (this.zone.equalsIgnoreCase(server.getZone())) {
                      local.add(server);
                  }
              }
              if (!local.isEmpty()) {
                  return local;
              }
          }
          return output;
      }
      

      即consumer配置了zone并且ZoneAffinityServerListFilter过滤后server列表没变化,则ZonePreferenceServerListFilter执行亲和性过滤,强制和consumer配置的zone进行比对。

      那么分为以下情况:

      1. 如果亲和性zone对应的server只要存在,那么就使用亲和性zone的server。
      2. 如果亲和性zone对应的server全军覆没了(从Eureka上获取不到了),那么使用其他zone的server。
  2. 那么针对这种情况进行测试,看看是不是上述的过程:

    1. 首先测试provider正确设置了zone,但是consumer采用defaultZone的情况:

      配置图及测试情况如下:
      在这里插入图片描述

    2. 再测试provider设置了正确的zone,consumer也设置了对应的zone的情况:

      配置图及测试情况如下:
      在这里插入图片描述

    3. 再测试provider设置了正确的zone,consumer也设置了对应的zone,但是亲和性的zone中的实例全挂了:

      配置图及测试情况如下:
      在这里插入图片描述

    4. 结论,如果某个zone整个不可用,亲和过滤会导致consumer调用异常(降级),30秒后,eureka client更新,则选择其他可用zone。

    5. 如果要想避免这种情况(30秒的不可用),可以将客户端配置如下:

      ribbon: 
        NIWSServerListFilterClassName: com.netflix.loadbalancer.ZoneAffinityServerListFilter
      

      即使用ZoneAffinityServerListFilter(注意,springcloud默认的ZonePreferenceServerListFilter会导致30秒不可用问题),由于它会对区域亲和后的zone进行健康检查,故,当区域亲和后的zone不健康时,则不返回区域亲和的结果,所以可以保证在区域亲和的zone不可用时,使用其他的zone,详细请参考ServerListFilter

发布了62 篇原创文章 · 获赞 23 · 访问量 15万+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章