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萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章