一、使用Eureka Server搭建服務注冊中心
1.Maven依賴
<dependencies> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId> </dependency> </dependencies>
2.配置文件(application.yml)
server: port: 8761 eureka: evictionIntervalTimerInMs: 6000 instance: hostname: localhost client: registerWithEureka: false fetchRegistry: false serviceUrl: defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/ spring: application: name: blog-eureka-server
3.啟動類
package com.springcloud.blog; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer; @SpringBootApplication @EnableEurekaServer public class BlogEurekaServerApplication { public static void main(String[] args) { SpringApplication.run( BlogEurekaServerApplication.class, args ); } }
4.啟動效果
二、使用Eureka Client搭建服務提供者
1.Maven依賴
<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId> </dependency>
2.配置文件(application.yml)
# Tomcat server: tomcat: uri-encoding: UTF-8 max-threads: 1000 min-spare-threads: 30 port: 2020 servlet: context-path: /blog-admin ## spring相關配置 spring: application: name: blog-admin profiles: active: dev jackson: date-format: yyyy-MM-dd HH:mm:ss time-zone: GMT+8 servlet: multipart: max-file-size: 100MB max-request-size: 100MB enabled: true eureka: client: serviceUrl: defaultZone: http://localhost:8761/eureka/
3.啟動類
package com.springcloud.blog.admin; import com.alibaba.druid.spring.boot.autoconfigure.DruidDataSourceAutoConfigure; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.netflix.eureka.EnableEurekaClient; @SpringBootApplication(exclude = DruidDataSourceAutoConfigure.class) @EnableEurekaClient public class BlogAdminApplication{ public static void main(String[] args) { SpringApplication.run(BlogAdminApplication.class, args); } }
4.啟動后,回過頭看服務注冊中心,增加了一個服務提供者
三、相關解釋
1.配置文件內容
- eureka.client.register-with-eureka:由於該應用為注冊中心,所以設置為false,代表不向注冊中心注冊自己。
- eureka.client.fetch-registry:由於注冊中心的職責就是維護服務實例,它並不需要去檢索實例,所以也設置為為false。
- eureka.client.serviceUrl.defaultZone:注冊中心地址
- eureka.instance.lease-renewal-interval-in-seconds=30:定義服務續約任務的調用間隔時間,默認為30秒
- eureka.instance.lease-expiration-duration-in-seconds=90:用於定義服務時效時間,默認為90秒
2.基礎架構
Eureka服務治理基礎架構的三個核心要素。
- 服務注冊中心:Eureka提供的服務端,提供服務注冊與發現的功能
- 服務提供者:提供服務的應用,可以是SpringBoot應用,也可以是其他技術平台且遵循Eureka通信機制的應用。
- 服務消費者:消費者應用從服務注冊中心獲取服務列表,從而使消費者可以知道去何處調用其所需要的服務(很多時候服務提供者既是服務提供者也是服務消費者)
3.服務治理機制
服務提供者
(1)服務注冊
“服務提供者”在啟動的時候會通過發送REST請求的方式將自己注冊到Eureka Server上,同時帶上了自身服務的一些元數據信息。Eureka Server 接收到這個REST請求之后,將元數據信息存儲在一個雙層結構Map中,其中第一層的key是服務名,第二層的key是具體服務的實例名。
在服務注冊是,需要確認一下 eureka.client.register-with-eureka=true參數是否正確,該值默認為true。若設置為false將不會啟動注冊操作。
(2)服務同步
比方說兩個服務提供者分別注冊到兩個不同的服務注冊中心上,也就是說,它們的信息分別被兩個服務注冊中心所維護。此時,由於服務注冊中心之間因為互相注冊為服務,當服務提供者發送注冊請求到一個服務注冊中心是,它會將該請求轉發給集群中相連的其他注冊中心,從而實現注冊中心之間的服務同步。通過服務同步,兩個服務提供者的服務信息就可以通過這兩台服務注冊中心中的任意一台獲取到。
(3)服務續約
在注冊完服務之后,服務提供者會維護一個心跳用來持續告訴Eureka Server:”我還活着”,以防止Eureka Server的”剔除任務”將該服務實例從服務列表中排除出去,我們稱該操作作為服務續約。
服務消費者
(1)獲取服務
當我們啟動服務消費者的時候,它會發送一個REST請求給服務注冊中心,來獲取上面注冊的服務清單。為了性能考慮,Eureka Server會維護一份只讀的服務清單來返回給客戶端,同時該緩存清單會每隔30秒更新一次。
獲取服務是服務消費者的基礎,所以必須確保eureka.client.fetch-registry=true參數沒有被修改成false,該值默認為true。若希望修改緩存清單的更新時間,可以通過eureka.client.registry-fetch-interval-seconds=30參數進行修改,該參數默認值為30,單位為秒。
(2)服務調用
服務消費者在獲取服務清單后,通過服務名可以獲得具體提供服務的實例名和該實例的元數據信息。因為有了這些服務實例的詳細信息,所以客戶端可以根據自己的需求決定具體調用哪個實例,在Ribbon中會默認采用輪詢的方式進行調用,從而實現客戶端的負載均衡。
對於訪問實例的選擇,Eureka中有Region和Zone的概念,一個Region中可以包含多個Zone,每個服務客戶端需要被注冊到一個Zone中,所以每個客戶端對應一個Region和一個Zone。在進行服務調用的時候,優先訪問同處一個Zone中的服務提供方,若訪問不到,就訪問其他的Zone。
(3)服務下線
在系統運行過程中比如會面臨關閉或重啟服務的某個實例的情況,在服務關閉期間,我們自然不希望客戶端會繼續關閉了的實例。所以在客戶端程序中,當服務實例進行正常的關閉操作,它會觸發一個服務下線的REST請求給Eureka Server,告訴服務注冊中心:”我要下線了”。服務端在接收到請求之后,將該服務狀態置為下線,並把該下線事件傳播出去。
服務注冊中心
(1)失效剔除
有些時候,我們的服務實例並不一定會正常下線,可能由於內存溢出、網絡故障燈原因使得服務不能正常工作,而服務注冊中心並未收到”服務下線”的請求。為了從服務列表中將這些無法提供服務的實例剔除,Eureka Server在啟動的時候會創建一個定時任務,默認每隔一段時間(默認為60秒)將當前清單中超時(默認為90秒)沒有續約的服務剔除出去。
(2)自我保護
當我們在本地調試基於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的自我保護機制。
服務注冊到Eureka Server之后,會維護一個心跳連接,告訴Eureka Server自己還活着。Eureka Server在運行期間,會統計心跳失敗的比例在15分鍾之內是否低於85%,如果出現低於的情況(在單機調試的時候很容易滿足,實際在生產環境上通常是由於網絡不穩定導致),Eureka Server 會將當前的實例注冊信息保護起來,讓這些實例不會過期,盡可能保護這些注冊信息。但是,在這段保護期間內實例若出現問題,那么客戶端很容易拿到實際上不存在的服務實例,會出現調用失敗的情況,所以客戶端必須要有容錯機制,比如可以使用請求重試、斷路器等機制。
由於本地調試很容易觸發注冊中心的保護機制,這回使得注冊中心維護的服務實例不那么准確。所以,我們在本地進行開發的時候,可以使用eureka.server.enable-self-preservation=false 參數來關閉保護機制,以確保注冊中心可以將不可用的實例正確剔除。