本文是Spring Cloud系列的第四篇,前面三篇文章(使用Spring Cloud搭建服務註冊中心、使用Spring Cloud搭建高可用服務註冊中心、Spring Cloud中服務的發現與消費)我們帶大家搭建了服務註冊中心,向服務註冊中心註冊了服務,同時也發現和消費了服務。前面的文章我們是以實際代碼操作為主,這篇文章我想對前面三篇文章中涉及到的一些知識點再進行詳細的梳理,對於一些前面未涉及到的配置再做進一步的說明。
首先,通過前面三篇文章的學習,小夥伴們已經發現了Eureka服務治理體系中涉及到三個核心概念:服務註冊中心、服務提供者以及服務消費者,本文將從這三個方面來對Eureka服務治理體系進行一個詳細的說明。
服務提供者Eureka服務治理體系支持跨平臺,雖然我們前文使用了Spring Boot來作為服務提供者,但是對於其他技術平臺只要支持Eureka通信機制,一樣也是可以作為服務提供者,換句話說,服務提供者既可以是Java寫的,也可以是python寫的,也可以是js寫的。這些服務提供者將自己註冊到Eureka上,供其它應用發現然後調用,這就是我們的服務提供者,服務提供者主要有如下一些功能:
服務註冊服務提供者在啟動的時候會通過發送REST請求將自己註冊到Eureka Server上,同時還攜帶了自身服務的一些元數據信息。Eureka Server在接收到這個REST請求之後,將元數據信息存儲在一個雙層結構的Map集合中,第一層的key是服務名,第二層的key是具體服務的實例名,我們在上篇文章最後展示出來的截圖中,大家也可以看出一些端倪,如下:
同時,我們在服務註冊時,需要確認一下eureka.client.register-with-eureka=true配置是否正確,該值默認就為true,表示啟動註冊操作,如果設置為false則不會啟動註冊操作。
服務同步再說服務同步之前,我先描述一個場景:首先我有兩個服務註冊中心,地址分別是http://localhost:1111和http://localhost:1112,然後我還有兩個服務提供者,地址分別是http://localhost:8080和http://localhost:8081,然後我將8080這個服務提供者註冊到1111這個註冊中心上去,將8081這個服務提供者註冊到1112這個註冊中心上去,此時我在服務消費者中如果只向1111這個註冊中心去查找服務提供者,那麼是不是只能獲取到8080這個服務而獲取不到8081這個服務?大家看下面一張圖:
答案是服務消費者可以獲取到兩個服務提供者提供的服務。雖然兩個服務提供者的信息分別被兩個服務註冊中心所維護,但是由於服務註冊中心之間也互相註冊為服務,當服務提供者發送請求到一個服務註冊中心時,它會將該請求轉發給集群中相連的其他註冊中心,從而實現註冊中心之間的服務同步,通過服務同步,兩個服務提供者的服務信息我們就可以通過任意一臺註冊中心來獲取到。OK,下面我們來通過一個簡單的案例來驗證一下我們上面的理論:
eureka-server工程我們前面已經分別創建了application-peer1.properties和application-peer2.properties配置文件,如下:
application-peer1.properties:
spring.application.name=eureka-serverserver.port=1111eureka.instance.hostname=peer1eureka.client.register-with-eureka=trueeureka.client.service-url.defaultZone=http://peer2:1112/eureka/
application-peer2.properties:
spring.application.name=eureka-serverserver.port=1112eureka.instance.hostname=peer2eureka.client.register-with-eureka=trueeureka.client.service-url.defaultZone=http://peer1:1111/eureka/
然後我們通過下面兩行命令來啟動兩個服務註冊中心實例,如下:
java -jar eureka-server-0.0.1-SNAPSHOT.jar --spring.profiles.active=peer1 java -jar eureka-server-0.0.1-SNAPSHOT.jar --spring.profiles.active=peer2
然後我們給provider工程也創建兩個配置文件,分別為application-p1.properties和application-p2.properties,內容如下:
application-p1.properties:
spring.application.name=hello-serviceserver.port=8080eureka.client.service-url.defaultZone=http://peer1:1111/eureka
application-p2.properties:
spring.application.name=hello-serviceserver.port=8081eureka.client.service-url.defaultZone=http://peer2:1112/eureka
然後通過如下命令啟動兩個服務提供者的實例,如下:
java -jar provider-0.0.1-SNAPSHOT.jar --spring.profiles.active=p1 java -jar provider-0.0.1-SNAPSHOT.jar --spring.profiles.active=p2
OK,我們將8080這個服務註冊到1111這個服務註冊中心上去了,將8081這個服務註冊到1112這個服務註冊中心上去了。當兩個服務提供者都啟動成功之後,我們來看看兩個服務註冊中心的控制面板,如下: 、
最後我們再來看看ribbon-consumer的配置文件,如下:
spring.application.name=ribbon-consumerserver.port=9000eureka.client.service-url.defaultZone=http://peer1:1111/eureka
大家看到,我們運行消費端時只向1111那個服務註冊中心去獲取服務列表,但是在實際運行過程中8080和8081兩個服務提供者都有響應我們的請求,如下圖:
上面的日誌是8081列印的,下面的日誌是8080列印的,沒毛病。
服務續約在註冊完服務之後,服務提供者會維護一個心跳來不停的告訴Eureka Server:「我還在運行」,以防止Eureka Server將該服務實例從服務列表中剔除,這個動作稱之為服務續約,和服務續約相關的屬性有兩個,如下:
eureka.instance.lease-expiration-duration-in-seconds=90 eureka.instance.lease-renewal-interval-in-seconds=30
第一個配置用來定義服務失效時間,默認為90秒,第二個用來定義服務續約的間隔時間,默認為30秒。
服務消費者消費者主要是從服務註冊中心獲取服務列表,拿到服務提供者的列表之後,服務消費者就知道去哪裡調用它所需要的服務了,我們從下面幾點來進一步了解下服務消費者。
獲取服務當我們啟動服務消費者的時候,它會發送一個REST請求給服務註冊中心來獲取服務註冊中心上面的服務提供者列表,而Eureka Server上則會維護一份只讀的服務清單來返回給客戶端,這個服務清單並不是實時數據,而是一份緩存數據,默認30秒更新一次,如果想要修改清單更新的時間間隔,可以通過eureka.client.registry-fetch-interval-seconds=30來修改,單位為秒(注意這個修改是在eureka-server上來修改)。另一方面,我們的服務消費端要確保具有獲取服務提供者的能力,此時要確保eureka.client.fetch-registry=true這個配置為true。
服務調用服務消費者從服務註冊中心拿到服務提供者列表之後,通過服務名就可以獲取具體提供服務的實例名和該實例的元數據信息,客戶端將根據這些信息來決定調用哪個實例,我們之前採用了Ribbon,Ribbon中默認採用輪詢的方式去調用服務提供者,進而實現了客戶端的負載均衡。
服務下線服務提供者在運行的過程中可能會發生關閉或者重啟,當服務進行正常關閉時,它會觸發一個服務下線的REST請求給Eureka Server,告訴服務註冊中心我要下線了,服務註冊中心收到請求之後,將該服務狀態置為DOWN,表示服務已下線,並將該事件傳播出去,這樣就可以避免服務消費者調用了一個已經下線的服務提供者了。
服務註冊中心服務註冊中心就是Eureka提供的服務端,它提供了服務註冊與發現功能。
失效剔除上面我們說到了服務下線問題,正常的服務下線發生流程有一個前提那就是服務正常關閉,但是在實際運行中服務有可能沒有正常關閉,比如系統故障、網絡故障等原因導致服務提供者非正常下線,那麼這個時候對於已經下線的服務Eureka採用了定時清除:Eureka Server在啟動的時候會創建一個定時任務,每隔60秒就去將當前服務提供者列表中超過90秒還沒續約的服務剔除出去,通過這種方式來避免服務消費者調用了一個無效的服務。
自我保護我們在前三篇文章中給大家看的截圖上,都有這樣一個警告,如下圖:
這個警告實際上就是觸發了Eureka Server的自我保護機制。Eureka Server在運行期間會去統計心跳失敗比例在15分鐘之內是否低於85%,如果低於85%,Eureka Server會將這些實例保護起來,讓這些實例不會過期,但是在保護期內如果服務剛好這個服務提供者非正常下線了,此時服務消費者就會拿到一個無效的服務實例,此時會調用失敗,對於這個問題需要服務消費者端要有一些容錯機制,如重試,斷路器等。我們在單機測試的時候很容易滿足心跳失敗比例在15分鐘之內低於85%,這個時候就會觸發Eureka的保護機制,一旦開啟了保護機制,則服務註冊中心維護的服務實例就不是那麼準確了,此時我們可以使用eureka.server.enable-self-preservation=false來關閉保護機制,這樣可以確保註冊中心中不可用的實例被及時的剔除。
OK,以上就是我們對Eureka中服務註冊中心、服務提供者、服務消費者三個核心概念的一些理解,有問題歡迎留言討論。
更多JavaEE資料請關注公眾號:
以上。。