1.預備知識
1.1 Region 與 Zone
1.1.1 概念
Eureka 中具有 Region 與 Availability Zone(簡稱 AZ)概念,是雲計算中的概念。
為了友善不同地理區域中使用者的使用
,大型雲服務提供商一般會根據使用者需求量在不同的城市、省份、國家或洲建立不同的大型雲計算機房。這些不同區域機房間一般是不能“内網連通”的。這些區域就稱為一個 Region。
這裡存在一個問題:同一 Region 機房是如何實作
同域容災
的?為了增強容災能力,在一個 Region 中又設定了不同的
Availability Zone
。這些 AZ 間實作了
内網連通
,且使用者可以根據自己所在的具體位置自動選擇同域中的不同 AZ。當使用者所要通路的 AZ 出現問題後,系統會自動切換到其它可用的 AZ。
例如,AWS 将全球劃分為了很多的 Region,例如美國東部區、美國西部區、歐洲區、非洲開普敦區、亞太區等。像 Eureka 系統架構圖中的 us-east-1c、us-east-1d、us-east-1e 就是 us-east-1 這個 Region 中的 c、d、e 三個 AZ。
再如,阿裡雲在我國境内的 Region 有杭州、北京、深圳、青島、香港等,境外 Region有亞太東南 1 區(新加坡)、亞太東南 2 區(悉尼)、亞太東北 1 區(東京)。
1.1.2 Eureka 中的 Region 與 Zone 配置
(1) 需求
假設某公司的伺服器有 Beijing、Shanghai 等多個 Region。Beijing 這個 Region 中存在兩個 AZ,分别是 bj-1 與 bj-2,每個 AZ 中有三台 Eureka Server。
h-1 與 h-2 兩台主機提供的都是相同的 Servivce 服務,根據地理位置的不同,這兩台主機分别注冊到了距離自己最近的不同 AZ 的 Eureka Server。
但是因為Region中的AZ都是内網聯通的,是以 整個Region中的每個Eureka Server資料都是一緻的。
(2) 主機配置
Eureka配置:
-
A、Server AZ bj-1
說明:bj-1 這個 Eureka Server 的 AZ 叢集中具有三台 Server,這三台 Server 的配置檔案,除了 server.port 不同外,其它配置完全相同。
這三個 Server 的 IP 與端口分别為:ip00:8000,ip01:8001,ip02:8002,該三台主機屬于同一個zone。
同時需要注意,defaultZone需要配置整個Region中所有的Eureka Server的位址
配置如下,隻展示了一個,另外兩個隻是端口不同,可以看到是通過中繼資料配置zone的:
-
B、 Server AZ bj-2
說明:bj-2 這個 AZ 叢集中具有三台 Server,這三台 Server 的配置檔案,除了 server.port不同外,其它配置完全相同。
這三個 Server 的 IP 與端口分别為:ip10:8000,ip11:8001,ip12:8002,該三台主機屬于同一個zone。
同時需要注意,defaultZone需要配置整個Region中所有的Eureka Server的位址
配置如下,也是隻展示了一個,另外兩個隻是端口不同:
Zuul配置:
- C、 Zuul AZ bj-1
- D、Zuul AZ bj-2
Service配置:
這兩個微服務名稱是相同的,隻是在不同的zone
- E、 Service AZ bj-1
- F、 Service AZ bj-2
可以通過以下配置,讓Eureka Client優先選擇相同zone的應用 如果目前region中的應用都不能用,可以用以下參數指定其他region
1.2 核心類
(1) InstanceInfo
簡單來說,該類代表的就是系統資料庫中的一個主機執行個體資訊。每一個注冊到Eureka Server的主機對應一個該類的執行個體。
兩個時間戳:
後面分析源碼會多次看到兩個時間戳,先簡單介紹一下:
- lastDirtyTimestamp:記錄 instanceInfo 在
被修改的時間。Client 端
, instanceInfo 中任何資訊被修改(資料中心資訊、續約配置資訊、狀态等),都會更新該時間戳。這個字段隻會在client端被更新
- lastUpdatedTimestamp:記錄 instanceInfo 在
被修改的時間。Server 端
,server端通常隻會修改 instanceInfo 的狀态資訊(我暫時隻發現隻修改了狀态資訊)。這個字段隻會在server端被更新
兩個狀态:
instanceInfo中一共有兩個狀态overriddenStatus和status。
關于overriddenStatus,字面意思是覆寫狀态,它是一個“外部”狀态,可以由外部任何程式進行修改,例如之前示範服務平滑上下線,通過actuator修改伺服器(主機執行個體)狀态,修改的值其實就是overriddenStatus。而overriddenStatus并不代表伺服器真正狀态。
而status是真正的伺服器狀态,但是status的值是通過一套規則計算出來的,其中就需要overriddenStatus,後面分析源碼會看到。
三個修改狀态的方法:
-
setOverriddenStatus
該方法僅會在 Eureka Server 端被調用。(通過actuator修改狀态UP/DOWN…由用戶端發起請求,服務端處理請求的時候調用)
-
setStatusWithoutDirty
該方法僅會在 Eureka Server 端被調用,在修改 status 時不記錄修改時間戳。
-
setStatus
該方法在 Eureka Client 端調用(定時檢測配置更新的時候),用于設定 instance 的服務狀态。
//InstanceInfo.java /** * Set the status for this instance. * * @param status status for this instance. * @return the prev status if a different status from the current was set, null otherwise */ public synchronized InstanceStatus setStatus(InstanceStatus status) { if (this.status != status) { InstanceStatus prev = this.status;//記錄之前狀态 this.status = status;//更新新的狀态 setIsDirty();//設定dirty标志,髒資料标記,表示用戶端和服務端之間資料不一緻,需要同步 return prev;//傳回之前的狀态 } return null; } /** * Sets the dirty flag so that the instance information can be carried to * the discovery server on the next heartbeat. * 設定dirty标志,以便可以将執行個體資訊傳輸到下一個heartbeat上的發現伺服器。 * * 簡單來說就是變成髒資料以後,用戶端會發起請求和服務端進行資料同步,後面源碼分析會看到 */ public synchronized void setIsDirty() { isInstanceInfoDirty = true; lastDirtyTimestamp = System.currentTimeMillis(); }
看下都有哪些狀态:
- UP:對外提供服務的 啟動狀态,
Ribbon負載均衡的時候,隻有當 status 的狀态為 UP 時,才能被服務發現,進行服務調用
- OUT_OF_SERVICE:和DOWN效果一樣,但一般是我們手動通過actuator修改狀态,讓其不提供服務,當然手動修改為DOWN也可以
- DOWN:一般不是手動修改,而是client和server心跳發生異常的時候,系統自動修改為DOWN
- STARTING:client啟動過程、初始化過程中的狀态,啟動完成後狀态就變了,一般維持的時間不會很長
- UNKNOWN:一般來說就是overriddenStatus的初始值
InstanceInfo重寫了 equals()方法:
InstanceInfo重寫了 equals()方法,将來兩個InstanceInfo比較,主要看InstanceInfo的id:
(2) Application
也是系統資料庫中的一部分,簡單來說,系統資料庫中同一個微服務的所有提供者的執行個體InstanceInfo資訊都會維護在該類中,即一種微服務對應一個Application執行個體。
(3) Applications
這個就是我們說的系統資料庫,維護的是整個從服務端擷取的系統資料庫資訊。
說明一點:這個類專門為用戶端使用的,實際上服務端的系統資料庫資料結構,就是一個雙層map,後面源碼分析會看到。
(4) Jersey 架構
Eureka Client 與 Eureka Server 間的通信,及各個 Eureka Server 間的通信,使用的是 Jersey 架構完成的(
都是通過http協定進行通信的
)。
Jersey 架構是一個開源的 RESTful 架構。其功能與 SpringMVC 的相同。不同的是 SpringMVC 的處理器是 Controller,而 Jersey 的是 Resource。
2. Eureka Client 自動配置類的加載
PS:對Spring boot自動配置不熟的朋友,可以先去看一下關于SpringBoot自動配置的文章。我的部落格裡也有。
這裡我們主要關注Eureka Client自動配置的時候都加載了哪些東西
入口從Eureka Client依賴開始:
找到對應的依賴的具體代碼:
Eureka Client相關配置類的加載
關于@EnableConfigurationProperties注解:
可以看到對于@ConfigurationProperties的類的處理,可以直接在注解的value屬性指定相應類名進行注冊,或者通過 @Bean方法注冊。EurekaClientAutoConfiguration是通過@Bean的方式:
- EurekaClientConfig
- EurekaInstanceConfig
Eureka Client 的建立
我們現在看我們最核心的EurekaClient的建立
問題1:
看下@ConditionalOnMissingBean注解的search屬性:
對應有三種政策:
PS:當然判斷的條件和Bean加載的順序也有關,這個其實是SpringBoot自動配置的知識點,不是本篇重點。
問題2:
在講Spring Cloud Config自動更新配置的時候,其實用過這個注解,這個注解可以讓Spring容器重新整理的時候,讓目前執行個體重新生成新的執行個體。
問題3:
懶加載,簡單來說就是如果不從Spring容器中擷取這個bean執行個體,或者被其他執行個體引用,就不會對該bean進行初始化。
即隻有用到的時候才會初始化。
問題4:
看一下@ConditionalOnMissingRefreshScope注解:
- Conditional注解:
- 看下具體的條件,OnMissingRefreshScopeCondition類:
回過頭看@ConditionalOnRefreshScope注解對比以下,看到條件剛好是相反的:
是以這兩個内置配置類不會同時起作用: