服務治理是微服務架構中最爲核心和基礎的模塊,它主要用來實現各個微服務實例的自動化註冊和發現。java
Spring Cloud Eureka是Spring Cloud Netflix微服務套件中的一部分,它基於Netflix Eureka作了二次封裝。主要負責完成微服務架構中的服務治理功能。spring
Eureka服務治理體系以下:api
在服務治理框架中,一般都會構建一個註冊中心,每一個服務單元向註冊中心登記本身提供的服務,包括服務的主機與端口號、服務版本號、通信協議等一些附加信息。註冊中心按照服務名分類組織服務清單,同時還須要以心跳檢測的方式去監測清單中的服務是否可用,若不可用須要從服務清單中剔除,以達到排除故障服務的效果。瀏覽器
在服務治理框架下,服務間的調用再也不經過指定具體的實例地址來實現,而是經過服務名發起請求調用實現。服務調用方經過服務名從服務註冊中心的服務清單中獲取服務實例的列表清單,經過指定的負載均衡策略取出一個服務實例位置來進行服務調用。緩存
Spirng Cloud Eureka使用Netflix Eureka來實現服務註冊與發現。它既包含了服務端組件,也包含了客戶端組件,而且服務端與客戶端均採用java編寫,因此Eureka主要適用於經過java實現的分佈式系統,或是JVM兼容語言構建的系統。Eureka的服務端提供了較爲完善的REST API,因此Eureka也支持將非java語言實現的服務歸入到Eureka服務治理體系中來,只須要其餘語言平臺本身實現Eureka的客戶端程序。目前.Net平臺的Steeltoe、Node.js的eureka-js-client等都已經實現了各自平臺的Ereka客戶端組件。安全
Eureka服務端,即服務註冊中心。它同其餘服務註冊中心同樣,支持高可用配置。依託於強一致性提供良好的服務實例可用性,能夠應對多種不一樣的故障場景。網絡
Eureka服務端支持集羣模式部署,當集羣中有分片發生故障的時候,Eureka會自動轉入自我保護模式。它容許在分片發生故障的時候繼續提供服務的發現和註冊,當故障分配恢復時,集羣中的其餘分片會把他們的狀態再次同步回來。集羣中的的不一樣服務註冊中心經過異步模式互相複製各自的狀態,這也意味着在給定的時間點每一個實例關於全部服務的狀態可能存在不一致的現象。架構
Eureka客戶端,主要處理服務的註冊和發現。客戶端服務經過註冊和參數配置的方式,嵌入在客戶端應用程序的代碼中。在應用程序啓動時,Eureka客戶端向服務註冊中心註冊自身提供的服務,並週期性的發送心跳來更新它的服務租約。同時,他也能從服務端查詢當前註冊的服務信息並把它們緩存到本地並週期行的刷新服務狀態。app
在服務治理框架中,一般都會構建一個註冊中心,每一個服務單元向註冊中心登記本身提供的服務,包括服務的主機與端口號、服務版本號、通信協議等一些附加信息。註冊中心按照服務名分類組織服務清單,同時還須要以心跳檢測的方式去監測清單中的服務是否可用,若不可用須要從服務清單中剔除,以達到排除故障服務的效果。負載均衡
建立一個Spring Boot工程,命名問Eureka-Server,並在pom文件中引入依賴:
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-eureka-server</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>${spring-cloud.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
在默認配置下,Eureka Server會將本身也做爲客戶端來嘗試註冊本身,咱們須要禁用它的客戶端禁用行爲。
下面是一個Eureka Server的application.properites的相關配置:
#服務註冊中心端口號
server.port=1110
#服務註冊中心實例的主機名
eureka.instance.hostname=localhost
#是否向服務註冊中心註冊本身
eureka.client.register-with-eureka=false
#是否檢索服務
eureka.client.fetch-registry=false
#服務註冊中心的配置內容,指定服務註冊中心的位置
eureka.client.serviceUrl.defaultZone=http://${eureka.instance.hostname}:${server.port}/eureka/
經過@EnableEurekaServer註解啓動服務註冊中心,以下:
import org.springframework.boot.SpringApplication;
importorg.springframework.boot.autoconfigure.SpringBootApplication;
importorg.springframework.cloud.netflix.eureka.server.EnableEurekaServer;
@EnableEurekaServer
@SpringBootApplication
public class IefopEurekaServerApplication {
publicstatic void main(String[] args) {
SpringApplication.run(IefopEurekaServerApplication.class,args);
}
}
考慮到發生故障的狀況,服務註冊中心發生故障必將會形成整個系統的癱瘓,所以須要保證服務註冊中心的高可用。
Eureka Server在設計的時候就考慮了高可用設計,在Eureka服務治理設計中,全部節點既是服務的提供方,也是服務的消費方,服務註冊中心也不例外。
Eureka Server的高可用實際上就是將本身作爲服務向其餘服務註冊中心註冊本身,這樣就能夠造成一組互相註冊的服務註冊中心,以實現服務清單的互相同步,達到高可用的效果。
Eureka Server的同步遵循着一個很是簡單的原則:只要有一條邊將節點鏈接,就能夠進行信息傳播與同步。能夠採用兩兩註冊的方式實現集羣中節點徹底對等的效果,實現最高可用性集羣,任何一臺註冊中心故障都不會影響服務的註冊與發現
(1)建立application-peer1.properties
server.port=1111
eureka.instance.hostname=master
eureka.client.register-with-eureka=false
eureka.client.fetch-registry=false
eureka.instance.preferIpAddress=true
eureka.server.enableSelfPreservation=false
eureka.client.serviceUrl.defaultZone=http://backup1:1112/eureka/,http://backup2:1113/eureka/
(2)建立application-peer2.properties
server.port=1112
eureka.instance.hostname=backup1
eureka.client.register-with-eureka=false
eureka.client.fetch-registry=false
eureka.instance.preferIpAddress=true
eureka.server.enableSelfPreservation=false
eureka.client.serviceUrl.defaultZone=http://master:1111/eureka/,http://backup2:1113/eureka/
(3)建立application-peer3.properties
server.port=1113
eureka.instance.hostname=backup2
eureka.client.register-with-eureka=false
eureka.client.fetch-registry=false
eureka.instance.preferIpAddress=true
eureka.server.enableSelfPreservation=false
eureka.client.serviceUrl.defaultZone=http://master:1111/eureka/,http://backup1:1112/eureka/
(4) 在hosts文件中增長以下配置
127.0.0.1 master
127.0.0.1 backup1
127.0.0.1 backup2
有些時候,咱們的服務實例並不必定會正常下線,可能因爲內存溢出、網絡故障等緣由使服務不能正常運做。而服務註冊中心並未收到「服務下線」的請求,爲了從服務列表中將這些沒法提供服務的實例剔除,Eureka Server在啓動的時候會建立一個定時任務,默認每隔一段時間(默認爲60秒)將當前清單中超時(默認爲90秒)沒有續約的服務剔除出去。
服務註冊到Eureka Server後,會維護一個心跳鏈接,告訴Eureka Server本身還活着。Eureka Server在運行期間會統計心跳失敗的比例在15分鐘以以內是否低於85%,若是出現低於的狀況,Eureka Server會將當前實例註冊信息保護起來,讓這些實例不會過時。這樣作會使客戶端很容易拿到實際已經不存在的服務實例,會出現調用失敗的狀況。所以客戶端要有容錯機制,好比請求重試、斷路器。
如下是自我保護相關的屬性:
eureka.server.enableSelfPreservation=true. 能夠設置改參數值爲false,以確保註冊中心將不可用的實例刪除
region和zone(或者Availability Zone)均是AWS的概念。在非AWS環境下,咱們能夠簡單地將region理解爲地域,zone理解成機房。一個region能夠包含多個zone,能夠理解爲一個地域內的多個不一樣的機房。不一樣地域的距離很遠,一個地域的不一樣zone間距離每每較近,也可能在同一個機房內。
region能夠經過配置文件進行配置,若是不配置,會默認使用us-east-1。一樣Zone也能夠配置,若是不配置,會默認使用defaultZone。
Eureka Server經過eureka.client.serviceUrl.defaultZone屬性設置Eureka的服務註冊中心的位置。
指定region和zone的屬性以下:
(1)eureka.client.availabilityZones.myregion=myzone# myregion是region
(2)eureka.client.region=myregion
Ribbon的默認策略會優先訪問通客戶端處於同一個region中的服務端實例,只有當同一個zone中沒有可用服務端實例的時候纔會訪問其餘zone中的實例。因此經過zone屬性的定義,配合實際部署的物理結構,咱們就能夠設計出應對區域性故障的容錯集羣。
咱們啓動了Eureka Server,而後在瀏覽器中輸入http://localhost:8761/後,直接回車,就進入了spring cloud的服務治理頁面,這麼作在生產環境是極不安全的,下面,咱們就給Eureka Server加上安全的用戶認證.
(1)pom文件中引入依賴
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
(2)serviceurl中加入安全校驗信息
eureka.client.serviceUrl.defaultZone=http://<username>:<password>@${eureka.instance.hostname}:${server.port}/eureka/
服務啓動後,訪問http://127.0.0.1:1110/能夠看到Eureka的信息面板。以下圖,目前Instancescurrently registered with Eureka一欄顯示註冊到服務註冊中心內的服務。
服務提供者在啓動的時候會經過REST請求的方式將本身註冊到Eureka Server上,同時帶上自身服務的一些元數據信息。Eureka Server接收到這個Rest請求以後,將元數據信息存儲在一個雙層結構的Map中,其中第一層的key是服務名。第二層的key 是具體服務的實例名。
在服務註冊時,須要確認一下eureka.client.register-with-eureka=true參數是否正確,該值默認爲true。若設置爲fasle將不會啓動註冊操做。
從eureka服務治理體系架構圖中能夠看到,不一樣的服務提供者能夠註冊在不一樣的服務註冊中心上,它們的信息被不一樣的服務註冊中心維護。
此時,因爲多個服務註冊中心互相註冊爲服務,當服務提供者發送註冊請求到一個服務註冊中心時,它會將該請求轉發給集羣中相連的其餘註冊中心,從而實現服務註冊中心之間的服務同步。經過服務同步,提供者的服務信息就能夠經過集羣中的任意一個服務註冊中心得到。
在註冊服務以後,服務提供者會維護一個心跳用來持續高速Eureka Server,「我還在持續提供服務」,不然Eureka Server的剔除任務會將該服務實例從服務列表中排除出去。咱們稱之爲服務續約。
下面是服務續約的兩個重要屬性:
(1)eureka.instance.lease-expiration-duration-in-seconds
leaseExpirationDurationInSeconds,表示eureka server至上一次收到client的心跳以後,等待下一次心跳的超時時間,在這個時間內若沒收到下一次心跳,則將移除該instance。
(2)eureka.instance.lease-renewal-interval-in-seconds
leaseRenewalIntervalInSeconds,表示eureka client發送心跳給server端的頻率。若是在leaseExpirationDurationInSeconds後,server端沒有收到client的心跳,則將摘除該instance。除此以外,若是該instance實現了HealthCheckCallback,並決定讓本身unavailable的話,則該instance也不會接收到流量。
建立一個Spring Boot工程,命名問Eureka-Client,並在pom文件中引入依賴:
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-eureka</artifactId>
</dependency>
</dependencies>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>${spring-cloud.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
在Eureka客戶端須要在appilication.properties文件中指定服務註冊中心的地址
eureka.port=1110
eureka.instance.hostname=localhost
#在此指定服務註冊中心地址
eureka.client.serviceUrl.defaultZone=http://${eureka.instance.hostname}:${eureka.port}/eureka/
在主類中加入@EnableEurekaClient註解啓動Eureka客戶端,以下:
package com.shl.iefop;
importorg.springframework.boot.SpringApplication;
importorg.springframework.boot.autoconfigure.SpringBootApplication;
importorg.springframework.cloud.netflix.eureka.EnableEurekaClient;
@EnableEurekaClient
@SpringBootApplication
public class IefopEurekaClientApplication {
publicstatic void main(String[] args) {
SpringApplication.run(IefopEurekaClientApplication.class,args);
}
}
消費者服務啓動時,會發送一個Rest請求給服務註冊中心,來獲取上面註冊的服務清單。爲了性能考慮,Eureka Server會維護一份只讀的服務註冊清單來返回給客戶端,同時該緩存清單默認會每隔30秒更新一次。
下面是獲取服務的兩個重要的屬性:
(1) eureka.client.fetch-registry
是否須要去檢索尋找服務,默認是true
(2)eureka.client.registry-fetch-interval-seconds
表示eureka client間隔多久去拉取服務註冊信息,默認爲30秒,對於api-gateway,若是要迅速獲取服務註冊狀態,能夠縮小該值,好比5秒
服務消費者在獲取服務清單後,經過服務名能夠獲取具體提供服務的實例名和該實例的元數據信息。由於有這些服務實例的詳細信息,因此客戶端能夠根據本身的須要決定具體調用哪一個實例,在Ribbon中會默認採用輪詢的方式進行調用,從而實現客戶端的負載均衡。
在系統運行過程當中必然會面臨關閉或重啓服務的某個實例的狀況,在服務關閉操做時,會觸發一個服務下線的Rest服務請求給Eureka Server,告訴服務註冊中心:「我要下線了。」服務端在接收到該請求後,將該服務狀態置位下線(DOWN),並把該下線事件傳播出去。
eureka實例的狀態頁面和健康監控的url默認爲spring boot actuator提供的/info端點和/health端點。咱們必須確保Eureka客戶端的/health端點在發送元數據的時候,是一個可以被註冊中心訪問到的地址,不然服務註冊中心不會根據應用的健康檢查來更改狀態(僅當開啓了healthcheck功能時,以該端點信息做爲健康檢查標準)。而若是/info端點不正確的話,會致使在Eureka面板中單擊服務時,沒法訪問到服務實例提供的信息接口。
大多數狀況下,咱們不須要修改這個幾個url配置。可是當應用不使用默認的上下文(context path或servlet path,好比配置server.servletPath=/test),或者管理終端路徑(好比配置management.contextPath=/admin)時,咱們須要修改健康檢查和狀態頁的url地址信息。
application.yml配置文件以下:
server.context-path=/helloeureka
//下面配置爲相對路徑,也支持配置成絕對路徑,例如須要支持https
eureka.instance.health-check-url-path=${server.context-path}/health
eureka.instance.status-page-url-path=${server.context-path}/info
元數據是Eureka客戶端在向服務註冊中心發送註冊請求時,用來描述自身服務信息的對象,其中包含了一些標準化的元數據,好比服務名稱、實例名稱、實例IP、實例端口等用於服務治理的重要信息;以及一些用於負載均衡策略或是其餘特殊用途的自定義元數據信息。
咱們能夠經過eureka.instance.<properties>=<value>的格式對標準化元數據直接進行配置,其中<properties>就是EurekaInstanceConfigBean對象中的成員變量。而對於自定義元數據,能夠經過eureka.instance.metadataMap.<key>=<value>的格式來進行配置。好比:
eureka.instance.metadataMap.zone=tianjin
//隨機生成實例名
eureka.instance.metadataMap.instanceId=${spring.application.name}:${random.value}
默認狀況下,Eureka中各個服務實例的健康檢測並非經過spring-boot-acturator模塊的/health端點來實現的,而是依靠客戶端心跳的方式來保持服務實例的存活。在Eureka的服務續約與剔除機制下,客戶端的健康狀態從註冊到註冊中心開始都會處於UP狀態,除非心跳終止一段時間以後,服務註冊中心將其剔除。默認的心跳實現方式能夠有效檢查客戶端進程是否正常運做,但卻沒法保證客戶端應用可以正常提供服務。
在Spring Cloud Eureka中,能夠把Eureka客戶端的健康檢測交給spring-boot-actuator模塊的health端點,以實現更加全面的健康狀態維護,設置方式以下:
(1) 在pom.xml中引入spring-boot-starter-actuator模塊的依賴
(2) 在application.properties中增長參數配置eureka.client.healthcheck.enabled=true
除了上述配置參數外,下面整理了一些EurekaInstanceConfigBean中定義的配置參數以及對應的說明和默認值,這些參數均以eureka.instance爲前綴。
默認狀況下,Eureka使用Jersey和XStream配合JSON做爲Server與Client之間的通信協議。也能夠選擇實現本身的協議來代替。