1. 程式人生 > >高可用的服務註冊中心以及服務註冊發現簡單分析

高可用的服務註冊中心以及服務註冊發現簡單分析

現在我們的服務註冊中心以及服務提供者消費者都已經搭建完畢了,但是我們需要考慮一個問題就是 如果我們的服務註冊中心Eureka掛了怎麼辦?

高可用的服務註冊中心

服務註冊中心Eureka Server,是一個例項,當成千上萬個服務向它註冊的時候,它的負載是非常高的,這在生產環境上是不太合適的,接下來主要介紹怎麼將Eureka Server叢集化。
這裡我們建立三個註冊中心專案
這裡寫圖片描述

我們對每個專案的配置檔案進行改造
之前我們是將eureka.client.serviceUrl.defaultZone 指向自己的ip以及埠,現在我們將自己註冊在另外的註冊中心上,這樣彼此都作為微服務客戶端進行註冊,即實現了高可用。

#高可用服務註冊中心
#服務名
spring:
  application:
    name: spring-cloud-eureka
#暴露的埠號
server:
  port: 8761
eureka:
  instance:
    hostname: peer1
  client:
    serviceUrl:
      defaultZone: http://peer2:8760/eureka/,http://peer3:8759/eureka/
#    fetch-registry: false
#    register-with-eureka: false
#本身也會被當做Client,所以false來表明自己是一個eureka server.
#做註冊中心叢集的時候可以設定為true,這樣其他註冊中心就會當作服務進行註冊,而且會在available-replicas中 #但是(true,false)沒看出有什麼影響,我還在研究.....
spring:
  application:
    name: spring-cloud-eureka
server:
  port: 8760
eureka:
  instance:
    hostname: peer2
  client:
    serviceUrl:
      defaultZone: http://peer1:8761/eureka/,http://peer3:8759/eureka/
# fetch-registry: false # register-with-eureka: false
spring:
  application:
    name: spring-cloud-eureka
server:
  port: 8759
eureka:
  instance:
    hostname: peer3
  client:
    serviceUrl:
      defaultZone: http://peer1:8761/eureka/,http://peer2:8760/eureka/
#    fetch-registry: false
#    register-with-eureka: false

可以看到每個註冊中心都已經註冊到了Eureka上(這裡說一下fetch-registry register-with-eureka 這兩個配置,在高可用情況下最好設定成true 不過預設值就是true所以可以不寫,但是我發現設定成false 並沒有什麼區別,只是不在available-replicas 中 ,具體有什麼影響我還在研究,也希望知道的朋友告訴我一下哈~~~)

我們前面服務提供者和消費者的配置檔案中的url只需要配置成我們其中的一個註冊中心地址即可(而不是本例子中的三個),這是因為Eureka Server的同步遵循著一個非常簡單的原則:只要有一條邊將節點連線,就可以進行資訊傳播與同步
現在我們分別啟動我們前面的服務提供者與消費者,可以看到服務分別註冊到了三個註冊中心上了並且註冊中心之間也實現叢集
這裡寫圖片描述
這裡寫圖片描述
這裡寫圖片描述

我們在斷掉一個服務註冊中心
這裡寫圖片描述
接著訪問服務消費者
這裡寫圖片描述
可以看到我們的服務仍舊註冊在服務中心上,從而實現了服務註冊高可用,服務註冊中心掛了我們也不怕了

服務註冊發現簡單分析

接下來我們簡單分析一個服務註冊到Eureka中經歷了什麼
一個客戶端也可以說一個微服務註冊到Eureka做了兩步

  1. 在應用主類中配置了@EnableDiscoveryClient註解
  2. 在application.properties中用eureka.client.serviceUrl.defaultZone引數指定了服務註冊中心的位置
在整個微服務註冊過程中有了兩個重要的物件region、Zone

客戶端依次載入了兩個內容,第一個是Region,第二個是Zone
通過getRegion函式,它從配置中讀取了一個Region返回,所以一個微服務應用只可以屬於一個Region,

如果不特別配置,就預設為default。若我們要自己設定,可以通過eureka.client.region屬性來定義。
當我們沒有特別為Region配置Zone的時候,將預設採用defaultZone,
這也是我們之前配置引數eureka.client.serviceUrl.defaultZone的由來。
若要為應用指定Zone,我們可以通過eureka.client.availability-zones屬性來進行設定。

從該函式的return內容,我們可以Zone是可以有多個的,並且通過逗號分隔來配置。由此,我們可以判斷Region與Zone是一對多的關係。

在獲取了Region和Zone資訊之後,才開始真正載入Eureka Server的具體地址
當客戶端在服務列表中選擇例項進行訪問時,對於Zone和Region遵循這樣的規則:

優先訪問同自己一個Zone中的例項,其次才訪問其他Zone中的例項。
通過Region和Zone的兩層級別定義,配合實際部署的物理結構,我們就可以有效的設計出區域性故障的容錯叢集。

服務註冊 服務獲取與服務續約(定時任務,REST的請求)

“服務獲取”相對於“服務續約”更為獨立,“服務續約”與“服務註冊”在同一個if邏輯中,
這個不難理解,服務註冊到Eureka Server後,自然需要一個心跳去續約,防止被剔除,所以他們肯定是成對出現的。
從原始碼中,我們可以清楚看到了,對於服務續約相關的時間控制引數:

eureka.instance.lease-renewal-interval-in-seconds=30
eureka.instance.lease-expiration-duration-in-seconds=90

“服務獲取”的邏輯在獨立的一個if判斷中,其判斷依據就是我們之前所提到的eureka.client.fetch-registry=true引數,它預設是為true的,大部分情況下我們不需要關心
為了定期的更新客戶端的服務清單,以保證服務訪問的正確性,
“服務獲取”的請求不會只限於服務啟動,而是一個定時執行的任務
從原始碼中我們可以看到任務執行中的registryFetchIntervalSeconds引數對應eureka.client.registry-fetch-interval-seconds=30配置引數,它預設為30秒。

服務註冊中心處理

通過上面的原始碼分析,可以看到所有的互動都是通過REST的請求來發起的。
在註冊函式中,先呼叫publishEvent函式,將該新服務註冊的事件傳播出去,
然後呼叫com.netflix.eureka.registry.AbstractInstanceRegistry父類中的註冊實現,
將InstanceInfo中的元資料資訊儲存在一個ConcurrentHashMap<String, Map<String, Lease<InstanceInfo>>>物件中,
它是一個兩層Map結構,第一層的key儲存服務名:InstanceInfo中的appName屬性,第二層的key儲存例項名:InstanceInfo中的instanceId屬性。