1. 程式人生 > >SpringColud Eureka的服務註冊與發現

SpringColud Eureka的服務註冊與發現

## 一、Eureka簡介 > 本文中所有程式碼都會上傳到git上,請放心瀏覽 > 專案git地址:[https://github.com/839022478/Spring-Cloud](https://github.com/839022478/Spring-Cloud) 在傳統應用中,元件之間的呼叫,通過有規範的約束的介面來實現,從而實現不同模組間良好的協作。但是被拆分成微服務後,每個微服務例項的網路地址都可能動態變化,數量也會變化,使得原來硬編碼的地址失去了作用。需要一箇中心化的元件來進行服務的登記和管理,為了解決上面的問題,於是出現了服務治理,就是管理所有的服務資訊和狀態,也就是我們所說的**註冊中心** ### 1.1 註冊中心 > 比如我們去做火車或者汽車,需要去買票乘車,只看我們有沒有票(有沒有服務),有就去買票(獲取註冊列表),然後乘車(呼叫),不用關心到底有多少車在執行 **流程圖:** ![在這裡插入圖片描述](https://img-blog.csdnimg.cn/20200613132239477.png) 使用註冊中心,我們不需要關心有多少提供方,只管去呼叫就可以了,那麼註冊中心有哪些呢? **註冊中心:Eureka,Nacos,Consul,Zookeeper** 本文中講解的是比較火熱的Spring Cloud微服務下的Eureka,Eureka是Netflix開發的服務發現框架,是一個RESTful風格的服務,是一個用於服務發現和註冊的基礎元件,是搭建Spring Cloud微服務的前提之一,它遮蔽了Server和client的互動細節,使得開發者將精力放到業務上。 服務註冊與發現主要包括兩個部分:```服務端(Eureka Server)和客戶端(Eureka Client)``` - **服務端(Eureka Server):** 一個公共服務,為Client提供服務註冊和發現的功能,維護註冊到自身的Client的相關資訊,同時提供介面給Client獲取登錄檔中其他服務的資訊,使得動態變化的Client能夠進行服務間的相互呼叫。 - **客戶端(Eureka Client):** Client將自己的服務資訊通過一定的方式登記到Server上,並在正常範圍內維護自己資訊一致性,方便其他服務發現自己,同時可以通過Server獲取到自己依賴的其他服務資訊,完成服務呼叫,還內建了負載均衡器,用來進行基本的負載均衡 Eureka GIt官網:**[https://github.com/Netflix/Eureka](https://github.com/Netflix/Eureka)** ### 1.3 服務註冊與發現 **服務註冊與發現關係圖:** ![在這裡插入圖片描述](https://img-blog.csdnimg.cn/20200613153818891.png) ### 1.2 client功能和server功能 #### 1.2.1 client功能 1. 註冊:每個微服務啟動時,將自己的網路地址等資訊註冊到註冊中心,註冊中心會儲存(記憶體中)這些資訊。 2. 獲取服務登錄檔:服務消費者從註冊中心,查詢服務提供者的網路地址,並使用該地址呼叫服務提供者,為了避免每次都查登錄檔資訊,所以client會定時去server拉取登錄檔資訊到快取到client本地。 3. 心跳:各個微服務與註冊中心通過某種機制(心跳)通訊,若註冊中心長時間和服務間沒有通訊,就會登出該例項。 4. 呼叫:實際的服務呼叫,通過登錄檔,解析服務名和具體地址的對應關係,找到具體服務的地址,進行實際呼叫。 #### 1.2.2 server註冊中心功能 1. 服務登錄檔:記錄各個微服務資訊,例如服務名稱,ip,埠等。 登錄檔提供 查詢API(查詢可用的微服務例項)和管理API(用於服務的註冊和登出)。 2. 服務註冊與發現:註冊:將微服務資訊註冊到註冊中心。發現:查詢可用微服務列表及其網路地址。 3. 服務檢查:定時檢測已註冊的服務,如發現某例項長時間無法訪問,就從登錄檔中移除。 ## 二、Eureka單節點搭建 ### 2.1 pom.xml 在有的教程中,會引入```spring-boot-starter-web```,這個依賴其實不用,因為```spring-cloud-starter-netflix-eureka-server```的依賴已經包含了它,在pom依賴進去,就可以了 ```java org.springframework.cloud
spring-cloud-starter-netflix-eureka-server
``` ### 2.2 application.yml ```java server: port: 8500 eureka: client: #是否將自己註冊到Eureka Server,預設為true,由於當前就是server,故而設定成false,表明該服務不會向eureka註冊自己的資訊 register-with-eureka: false #是否從eureka server獲取註冊資訊,由於單節點,不需要同步其他節點資料,用false fetch-registry: false #設定服務註冊中心的URL,用於client和server端交流 service-url: defaultZone: http://localhost:8080/eureka/ ``` ### 2.3 服務端啟動類 啟動類上新增此註解標識該服務為配置中心 @EnableEurekaServer ```java import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer; @EnableEurekaServer @SpringBootApplication public class EurekaServerApplication { public static void main(String[] args) { SpringApplication.run(EurekaServerApplication.class, args); } } ``` ### 2.4 啟動 我們啟動```EurekaDemoApplication ```,然後在瀏覽器中輸入地址 ```http://localhost:8500/```,就可以啟動我們的 Eureka 了,我們來看下效果,出現了這個畫面,就說明我們已經成功啟動~,只是此時我們的服務中是還沒有客戶端進行註冊 ![在這裡插入圖片描述](https://img-blog.csdnimg.cn/20200613121605965.png) ## 三、服務註冊 **注意:在客戶端pom裡面我們需要加上```spring-boot-starter-web```,否則服務是無法正常啟動的** ### 3.1 pom.xml ```java org.springframework.boot
spring-boot-starter-web
org.springframework.cloud spring-cloud-starter-netflix-eureka-client ``` ### 3.2 application.yml ```java #註冊中心 eureka: client: #設定服務註冊中心的URL service-url: defaultZone: http://localhost:8500/eureka/ #服務名 instance: appname: mxn ``` ### 3.3 客戶端啟動類 在客戶端啟動類中我們需要加上 ```@EnableDiscoveryClient```註解 ```java import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.client.discovery.EnableDiscoveryClient; @EnableDiscoveryClient @SpringBootApplication public class EurekaClientApplication { public static void main(String[] args) { SpringApplication.run(EurekaClientApplication.class, args); } } ``` ### 3.4 檢視效果 工程啟動後,重新整理```http://localhost:8500/```頁面,我們可以發現服務註冊成功了 ![在這裡插入圖片描述](https://img-blog.csdnimg.cn/20200613150700145.png) 並且我們可以在idea日誌列印中看到```DiscoveryClient_MXN/DESKTOP-5BQ3UK8 - registration status: 204```,說明就是註冊成功了 Eureka Server與Eureka Client之間的聯絡主要通過心跳的方式實現。心跳(Heartbeat)即Eureka Client定時向Eureka Server彙報本服務例項當前的狀態,維護本服務例項在登錄檔中租約的有效性。 Eureka Client將定時從Eureka Server中拉取登錄檔中的資訊,並將這些資訊快取到本地,用於服務發現 ## 四、Eureka 端點 官網地址:[https://github.com/Netflix/eureka/wiki/Eureka-REST-operations](https://github.com/Netflix/eureka/wiki/Eureka-REST-operations) Eureka伺服器還提供了一個端點```(eureka/apps/{applicaitonName})```可以檢視所註冊的服務詳細資訊 。applicaitonName就是微服務的名稱,比如這裡我們訪問 ```http://localhost:8500/eureka/apps/mxn``` ![在這裡插入圖片描述](https://img-blog.csdnimg.cn/20200613151254473.png) ## 五、Eureka 原理 ### 5.1 本質 儲存了每個客戶端的註冊資訊。EurekaClient從EurekaServer同步獲取服務註冊列表。通過一定的規則選擇一個服務進行呼叫 ### 5.2 Eureka架構圖 ![在這裡插入圖片描述](https://img-blog.csdnimg.cn/20200613153937308.png) - **服務提供者:** 是一個eureka client,向Eureka Server註冊和更新自己的資訊,同時能從Eureka Server登錄檔中獲取到其他服務的資訊。 - **服務註冊中心:** 提供服務註冊和發現的功能。每個Eureka Cient向Eureka Server註冊自己的資訊,也可以通過Eureka Server獲取到其他服務的資訊達到發現和呼叫其他服務的目的。 - **服務消費者:** 是一個eureka client,通過Eureka Server獲取註冊到其上其他服務的資訊,從而根據資訊找到所需的服務發起遠端呼叫。 - **同步複製:** Eureka Server之間登錄檔資訊的同步複製,使Eureka Server叢集中不同登錄檔中服務例項資訊保持一致。 - **遠端呼叫:** 服務客戶端之間的遠端呼叫。 - **註冊:** Client端向Server端註冊自身的元資料以供服務發現。 - **續約:** 通過傳送心跳到Server以維持和更新登錄檔中服務例項元資料的有效性。當在一定時長內,Server沒有收到Client的心跳資訊,將預設服務下線,會把服務例項的資訊從登錄檔中刪除。 - **下線:** Client在關閉時主動向Server登出服務例項元資料,這時Client的服務例項資料將從Server的登錄檔中刪除。 - **獲取登錄檔:** Client向Server請求登錄檔資訊,用於服務發現,從而發起服務間遠端呼叫。 ### 5.3 Eureka自我保護 有時候我們會看到這樣的提示資訊:```EMERGENCY! EUREKA MAY BE INCORRECTLY CLAIMING INSTANCES ARE UP WHEN THEY'RE NOT. RENEWALS ARE LESSER THAN THRESHOLD AND HENCE THE INSTANCES ARE NOT BEING EXPIRED JUST TO BE SAFE.```,這是因為預設情況下,Eureka Server在一定時間內,沒有接收到某個微服務心跳,會將某個微服務登出(90S)。但是當網路故障時,微服務與Server之間無法正常通訊,上述行為就非常危險,因為微服務正常,不應該登出,它的指導思想就是 **寧可保留健康的和不健康的,也不盲目登出任何健康的服務** 我們也可以通過命令去關閉自我保護的功能: ``` eureka: server: enable-self-preservation: false ``` 那麼自我保護是如何觸發的呢? 自我保護機制的觸發條件是,當每分鐘心跳次數( ```renewsLastMin```) 小於 ```numberOfRenewsPerMinThreshold```時,並且開啟自動保護模式開關( ```eureka.server.enable-self-preservation = true```) 時,觸發自我保護機制,不再自動過期租約 上面我們所有的小於 ```numberOfRenewsPerMinThreshold```,到底是怎麼計算的呢,我們在eureka原始碼中可以得知 >
numberOfRenewsPerMinThreshold = expectedNumberOfRenewsPerMin * 續租百分比(預設為0.85) expectedNumberOfRenewsPerMin = 當前註冊的應用例項數 x 2 當前註冊的應用例項數 x 2 是因為,在預設情況下,註冊的應用例項每半分鐘續租一次,那麼一分鐘心跳兩次,因此 x 2 例如:我們有10個服務,期望每分鐘續約數:10 * 2=20,期望閾值:20*0.85=17,當少於17時,就會觸發自我保護機制 ![在這裡插入圖片描述](https://img-blog.csdnimg.cn/20200613163215966.png) ### 5.4 健康檢查 由於server和client通過心跳保持 服務狀態,而只有狀態為UP的服務才能被訪問。看eureka介面中的status。 ![在這裡插入圖片描述](https://img-blog.csdnimg.cn/20200613182030564.png) 比如心跳一直正常,服務一直UP,但是此服務DB(資料庫)連不上了,無法正常提供服務。 此時,我們需要將 微服務的健康狀態也同步到server。只需要啟動eureka的健康檢查就行。這樣微服務就會將自己的健康狀態同步到eureka。配置如下即可。 在client端配置:將自己的健康狀態傳播到server。 ``` eureka: client: healthcheck: enabled: true ``` ### 5.5 Eureka監聽事件 ```java import com.netflix.appinfo.InstanceInfo; import org.springframework.cloud.netflix.eureka.server.event.*; import org.springframework.context.event.EventListener; import org.springframework.stereotype.Component; import java.time.LocalDateTime; @Component public class CustomEvent { @EventListener public void listen(EurekaInstanceCanceledEvent event ) { System.out.println(LocalDateTime.now()+"服務下線事件:"+event.getAppName()+"---"+event.getServerId()); //發釘釘 } @EventListener public void listen(EurekaInstanceRegisteredEvent event) { InstanceInfo instanceInfo = event.getInstanceInfo(); System.out.println(LocalDateTime.now()+"服務上線事件:"+instanceInfo.getAppName()+"---"+instanceInfo.getInstanceId()); } @EventListener public void listen(EurekaInstanceRenewedEvent event) { System.out.println(LocalDateTime.now()+"服務續約/心跳上報事件:"+event.getAppName()+"---"+event.getServerId()); } @EventListener public void listen(EurekaRegistryAvailableEvent event) { System.out.println(LocalDateTime.now()+"註冊中心可用事件"); } @EventListener public void listen(EurekaServerStartedEvent event) { System.out.println(LocalDateTime.now()+"註冊中心啟動事件"); } } ``` ### 5.6 Renew: 服務續約 Eureka Client 會每隔 30 秒傳送一次心跳來續約。 通過續約來告知 Eureka Server 該 Eureka Client 執行正常,沒有出現問題。 預設情況下,如果 Eureka Server 在 90 秒內沒有收到 Eureka Client 的續約,Server 端會將例項從其登錄檔中刪除,此時間可配置,一般情況不建議更改。 ### 5.6 服務剔除 如果Eureka Client在註冊後,既沒有續約,也沒有下線(服務崩潰或者網路異常等原因),那麼服務的狀態就處於不可知的狀態,不能保證能夠從該服務例項中獲取到回饋,所以需要服務剔除此方法定時清理這些不穩定的服務,該方法會批量將登錄檔中所有過期租約剔除,剔除是定時任務,預設60秒執行一次。延時60秒,間隔60秒 **剔除的限制:** 1.自我保護期間不清除。 2.分批次清除。 ## 六、Eureka缺陷 由於叢集間的同步複製是通過HTTP的方式進行,基於網路的不可靠性,叢集中的Eureka Server間的登錄檔資訊難免存在不同步的時間節點,不滿足CAP中的C(資料一致性) ## 七、總結 中間我們講解了eureka的節點搭建,以及原理,對於現在很火熱的微服務,我們對Eureka是非常有必要進行了解的,如果覺得文章對你有幫助,來個點贊支援吧,如果對文章有疑問或建議,歡迎討論留言,謝