一、Eureka簡介
Eureka是一項基於REST(代表性狀態轉移)的服務,主要在AWS雲中用於定位服務,以實現負載均衡和中間層服務器的故障轉移。我們稱此服務為Eureka Server。Eureka還帶有一個基於Java的客戶端組件Eureka Client,它使與服務的交互更加容易。客戶端還具有一個內置的負載均衡器,可以執行基本的循環負載均衡。在Netflix,更復雜的負載均衡器將Eureka包裝起來,以基於流量,資源使用,錯誤條件等多種因素提供加權負載均衡,以提供出色的彈性。
Git地址:https://github.com/Netflix/eureka
服務治理
在傳統的rpc遠程調用框架中,管理每個服務於服務之間依賴關系比較復雜,所以需要使用服務治理,管理服務與服務之間依賴關系,可以實現服務調用、負載均衡、容錯等,實現服務發現與注冊
Spring Cloud封裝了Netflix公司開發的Eureka模塊來實現服務治理
服務注冊
Eureka采用了CS的設計架構,Eureka Server作為服務注冊功能的服務器,它是服務注冊中心,而系統中的其他服務,使用Eureka的客戶端連接到Eureka Server並維持心跳連接。這樣系統的維護人員就可以通過Eureka Server來監控系統中各個微服務是否正常運行。在服務注冊與發現中,有一個注冊中心。當服務器啟動的時候,會把當前自己服務器的信息,比如服務地址、通訊地址等以別名方式注冊到注冊中心上,另一方(消費者|服務提供者),以該別名的方式去注冊中心上獲取實際的服務通訊地址,然后在實現本地RPC調用RPC遠程調用框架核心設計思想:在於注冊中心,因為使用注冊中心管理每個服務與服務之間的一個依賴關系(服務治理概念)。在任何rpc遠程框架中,都會有一個注冊中心(存放服務地址相關信息(接口地址))
二、Eureka兩組件
Eureka Server
Eureka Server提供服務注冊服務,各個微服務節點通過配置啟動后,會在EurekaServer中進行注冊,這樣EurekaServer中的服務注冊表中將會存儲所有可用服務節點的信息,服務節點的信息可以在界面中直觀看到。
Eureka Client
Eureka Client通過注冊中心進行訪問是一個Java客戶端,用於簡化Eureka Server的交互,客戶端同時也具備一個內置的、使用輪詢(round-robin)負載算法的負載均衡器。在應用啟動后,將會向Eureka Server發送心跳(默認周期為30秒)。如果Eureka Server在多個心跳周期內沒有接收到某個節點的心跳。Eureka Server將會從服務注冊表中把這個服務節點移除(默認90秒)
三、Eureka架構
說明:
Register(服務注冊):把自己的IP和端口注冊給Eureka。
Renew(服務續約):發送心跳包,每30秒發送一次。告訴Eureka自己還活着。
Cancel(服務下線):當provider關閉時會向Eureka發送消息,把自己從服務列表中刪除。防止consumer調用到不存在的服務。
Get Registry(獲取服務注冊列表):獲取其他服務列表。
Replicate(集群中數據同步):eureka集群中的數據復制與同步。
Make Remote Call(遠程調用):完成服務的遠程調用。
四、單機版Eureka Server
五、集群版Eureka Server
注冊中心作為微服務架構中的核心功能,其重要性不言而喻。在實際生產中,都會去搭建應用的集群來保證服務高可用。Eureka Server注冊中心集群中每個節點都是平等的,集群中的所有節點同時對外提供服務的發現和注冊等功能。同時集群中每個Eureka Server節點又是一個微服務,也就是說,每個節點都可以在集群中的其他節點上注冊當前服務。又因為每個節點都是注冊中心,所以節點之間可以相互注冊當前節點中已注冊的服務,並發現其他節點中已注冊的服務。
搭建步驟
1、創建三個單機版的Eureka Server項目,分別為
test-springcloud-eureka-server8761
test-springcloud-eureka-server8762
test-springcloud-eureka-server8763
2、編輯項目test-springcloud-eureka-server8761的application.yml配置文件
1 # 端口 2 server: 3 port: 8761 4 5 spring: 6 application: 7 name: cloud-eureka-server 8 9 # Eureka配置 10 eureka: 11 instance: 12 # eureka服務端的實例名稱 13 hostname: eureka8761.com 14 client: 15 # false表示不向注冊中心注冊自己 16 register-with-eureka: false 17 # false表示自己端就是注冊中心,職責就是維護服務實例,並不需要去檢查服務 18 fetch-registry: false 19 # 設置與Eureka Server交互的地址查詢服務和注冊服務都需要依賴這個地址 20 service-url: 21 # 集群模式:設置服務注冊中心地址,指向其他注冊中心 22 defaultZone: http://eureka8762.com:8762/eureka,http://eureka8763.com:8763/eureka
同理配置其他2個節點的配置文件,不同地方有以下三點
# 端口 server.port # 實例主機名稱 eureka.instance.hostname # server-url eureka.client.server-url.defaultZone
3、更改主機的映射,hosts 文件
127.0.0.1 eureka8761.com 127.0.0.1 eureka8762.com 127.0.0.1 eureka8763.com
4、啟動三個注冊中心,使用地址:http://eureka8761.com:8761/,訪問8761節點
同理,可以使用http://eureka8762.com:8762/,http://eureka8763.com:8763/,訪問另外2個節點
5、Eureka Client 客戶端,在向集群模式Eureka注冊的時候,注冊地址是:
http://eureka8761.com:8761/eureka,http://eureka8762.com:8762/eureka,http://eureka8763.com:8763/eureka
同時向三個節點注冊
1 eureka: 2 client: 3 # 設置與Eureka Server交互的地址查詢服務和注冊服務都需要依賴這個地址 4 service-url: 5 defaultZone: http://eureka8761.com:8761/eureka,http://eureka8762.com:8762/eureka,http://eureka8763.com:8763/eureka
六、Eureka Server安全認證
Eureka Server作為Spring Cloud中的服務注冊中心,如果可以任意訪問的話,那么其安全性太低。所以Spring Cloud中也有為Eureka Server提供安全認證的方式。可以使用spring-boot-starter-security組件來為Eureka Server增加安全認證。
1、新增security的POM依賴:
1 <!-- spring boot security安全認證啟動器 --> 2 <dependency> 3 <groupId>org.springframework.boot</groupId> 4 <artifactId>spring-boot-starter-security</artifactId> 5 </dependency>
2、修改application.yml配置文件,增加安全認證信息、用戶名密碼、修改連接地址
1 spring: 2 application: 3 name: cloud-eureka-server 4 security: 5 user: 6 name: root 7 password: 123456 8 9 # Eureka配置 10 eureka: 11 client: 12 service-url: 13 # 集群模式:設置服務注冊中心地址,指向其他注冊中心 14 defaultZone: http://${spring.security.user.name}:${spring.security.user.password}@eureka8762.com:8762/eureka,http://${spring.security.user.name}:${spring.security.user.password}@eureka8763.com:8763/eureka 15 16 17 #安全認證信息 18 security: 19 basic: 20 enabled: true
完整配置如下:

1 # 端口 2 server: 3 port: 8761 4 5 spring: 6 application: 7 name: cloud-eureka-server 8 security: 9 user: 10 name: root 11 password: 123456 12 13 # Eureka配置 14 eureka: 15 instance: 16 # eureka服務端的實例名稱 17 hostname: eureka8761.com 18 client: 19 # false表示不向注冊中心注冊自己 20 register-with-eureka: false 21 # false表示自己端就是注冊中心,職責就是維護服務實例,並不需要去檢查服務 22 fetch-registry: false 23 # 設置與Eureka Server交互的地址查詢服務和注冊服務都需要依賴這個地址 24 service-url: 25 # 集群模式:設置服務注冊中心地址,指向其他注冊中心 26 defaultZone: http://${spring.security.user.name}:${spring.security.user.password}@eureka8762.com:8762/eureka,http://${spring.security.user.name}:${spring.security.user.password}@eureka8763.com:8763/eureka 27 28 29 #安全認證信息 30 security: 31 basic: 32 enabled: true
3、增加安全認證的配置類,WebSecurityConfig.java
由於新版的Spring Security啟用csrf防護后,會對post、delete、put等請求進行安全校驗。過程是,請求里必須攜帶crfs的tocken,如果請求里不帶有tocken時,服務器會認為該請求非法,請求就會被拒絕。不關閉,可能導致服務無法在注冊中心注冊
1 @EnableWebSecurity 2 @Configuration 3 public class WebSecurityConfig extends WebSecurityConfigurerAdapter { 4 5 @Override 6 protected void configure(HttpSecurity http) throws Exception { 7 8 // Spring Security啟用csrf防護后,會對post、delete、put等請求進行安全校驗。 9 // 過程是,請求里必須攜帶crfs的tocken,如果請求里不帶有tocken時,服務器會認為該請求非法,請求就會被拒絕。 10 // 默認開啟,關閉csrf過濾 11 http.csrf().disable(); 12 13 http 14 .authorizeRequests() 15 .anyRequest().authenticated() 16 .and() 17 .formLogin().and() 18 .httpBasic(); 19 } 20 21 }
4、重啟Eureka Server服務,使用地址:http://eureka8761.com:8761/login,進行訪問
需要登錄,輸入用戶名/密碼:root/123456
5、Eureka Client客戶端,修改配置,連接增加用戶名和密碼
1 # 端口 2 server: 3 port: 8001 4 5 spring: 6 application: 7 name: cloud-payment-service 8 security: 9 user: 10 name: root 11 password: 123456 12 13 eureka: 14 client: 15 # 表示將自己注冊進Eureka Server默認為true 16 register-with-eureka: true 17 # 是否從Eureka Server抓去已有的注冊信息,默認是true 18 fetch-registry: true 19 # 設置與Eureka Server交互的地址查詢服務和注冊服務都需要依賴這個地址 20 service-url: 21 defaultZone: http://${spring.security.user.name}:${spring.security.user.password}@eureka8761.com:8761/eureka,http://${spring.security.user.name}:${spring.security.user.password}@eureka8762.com:8762/eureka
6、重啟項目,打開Eureka注冊中心,查看是否注冊成功
七、Eureka自我保存模式
如果Eureka服務器檢測到數量超過預期的注冊客戶端已以不正當的方式終止了它們的連接,並且同時正等待逐出,則它們將進入自我保存模式。這樣做是為了確保災難性的網絡事件不會清除eureka注冊表數據,並將其傳播到下游的所有客戶端。
服務保護模式
服務保護模式(自我保護模式):一般情況下,微服務在Eureka上注冊后,會每30秒發送心跳包,Eureka通過心跳來判斷服務時候健康,同時會定期刪除超過90秒沒有發送心跳服務。
導致Eureka Server接收不到心跳包的可能:一是微服務自身的原因,二是微服務與Eureka之間的網絡故障。通常微服務的自身的故障只會導致個別服務出現故障,一般不會出現大面積故障,而網絡故障通常會導致Eureka Server在短時間內無法收到大批心跳。慮到這個區別,Eureka設置了一個閥值,當判斷掛掉的服務的數量超過閥值時,Eureka Server認為很大程度上出現了網絡故障,將不再刪除心跳過期的服務。
那么這個閥值是多少呢?Eureka Server在運行期間,會統計心跳失敗的比例在15分鍾內是否低於85%,如果低於85%,Eureka Server則任務是網絡故障,不會刪除心跳過期服務。
這種服務保護算法叫做Eureka Server的服務保護模式。
這種不刪除的,90秒沒有心跳的服務,稱為無效服務,但是還是保存在服務列表中。如果Consumer到注冊中心發現服務,則Eureka Server會將所有好的數據(有效服務數據)和壞的數據(無效服務數據)都返回給Consumer。
服務保護模式的存在必要性
因為同時保留"好數據"與"壞數據"總比丟掉任何數據要更好,當網絡故障恢復后,Eureka Server會退出"自我保護模式"。
Eureka還有客戶端緩存功能(也就是微服務的緩存功能)。即便Eureka Server集群中所有節點都宕機失效,微服務的Provider和Consumer都能正常通信。
微服務的負載均衡策略會自動剔除死亡的微服務節點(Robbin)。
只要Consumer不關閉,緩存始終有效,直到一個應用下的所有Provider訪問都無效的時候,才會訪問Eureka Server重新獲取服務列表。
關閉服務保護模式
可以通過全局配置文件來關閉服務保護模式,商業項目中不推薦關閉服務保護,因為網絡不可靠很容易造成網絡波動、延遲、斷線的可能。如果關閉了服務保護,可能導致大量的服務反復注冊、刪除、再注冊。導致效率降低。在商業項目中,服務的數量一般都是幾十個,大型的商業項目中服務的數量可能上百、數百,甚至上千:
1 eureka: 2 server: 3 # 是否開啟自我保護模式,默認是true 4 enable-self-preservation: false 5 # 掃描失效服務的時間間隔。單位 毫秒。 默認值 60 * 1000 6 eviction-interval-timer-in-ms: 1000
優雅關閉服務(優雅停服)
在Spring Cloud中,可以通過HTTP請求的方式,通知Eureka Client優雅停服,這個請求一旦發送到Eureka Client,那么Eureka Client會發送一個shutdown請求到Eureka Server,Eureka Server接收到這個shutdown請求后,會在服務列表中標記這個服務的狀態為down,同時Eureka Client應用自動關閉。這個過程就是優雅停服。
如果使用了優雅停服,則不需要再關閉Eureka Server的服務保護模式。
1、在Eureka Client中增加新的依賴actuator
1 <dependency> 2 <groupId>org.springframework.boot</groupId> 3 <artifactId>spring-boot-starter-actuator</artifactId> 4 </dependency>
2、Eureka Client默認不開啟優雅停服功能,需要在全局配置文件中新增如下內容
1 # 開啟應用關閉端口 2 management.endpoint.shutdown.enabled=true 3 # 暴露shutdown的web端口
3、發起shutdown請求:
必須通過POST請求向Eureka Client發起一個shutdown請求。請求路徑為:http://ip:port/shutdown。可以通過任意技術實現,如:HTTPClient、form表單,AJAX等。
建議使用優雅停服方式來關閉Application Service/Application Client服務。
八、Eureka 的常用配置項
1、通用配置
1 spring.application.name=xxxxxxxxxxxxx :應用名稱配置,將會出現在 Eureka 注冊中心 Application 列 2 server.port=8701 :應用端口,默認值為 8761 3 eureka.instance.hostname= server1 :服務注冊中心應用實例主機名 4 eureka.instance.ip-address=127.0.0.1 :應用實例ip 5 eureka.instance.prefer-ip-address=false :客戶端向注冊中心注冊時,相較於 hostname 是否有限使用 ip。在服務中心注冊后,鼠標放到服務的 Status 列的鏈接上,無需點擊,左下角能看出配置的變化。 6 eureka.instance.environment=dev :該實例的環境配置 7 eureka.client.register-with-eureka=false :是否將自己注冊到 Eureka 注冊中心。單機情況下的 Eureka Server 不需要注冊,集群的 Eureka Server 以及 Eureka Client 需要注冊。默認值 true 8 eureka.client.fetch-registry=false :是否需要從注冊中心檢索獲取服務的注冊信息。單機情況下的 Eureka Server 不需要獲取。集群的 Eureka Server 以及 Eureka Client 需要獲取。默認值 true 9 eureka.client.service-url.defaultZone= http://${spring.security.user.name}:${spring.security.user.password}@server1:8081/eureka/ :Eureka 服務的地址信息,中間的占位符為安全認證開啟時使用,如果 Eureka Server 為集群狀態,則逗號分隔,依次書寫即可。
2、Eureka Server 配置
1 eureka.server.enable-self-preservation = false :是否開啟自我保護模式,eureka server默認在運行期間會去統計心跳失敗比例在 15 分鍾之內是否低於 85%,如果低於 85%,Eureka Server 會將這些實例保護起來,讓這些實例不會過期,但是在保護期內如果服務剛好這個服務提供者非正常下線了,此時服務消費者就會拿到一個無效的服務實例,此時會調用失敗。默認 true 2 eureka.server.eviction-interval-timer-in-ms=10000 :掃描失效服務的時間間隔。單位 毫秒。 默認值 60 * 1000 3 security.basic.enabled=true :開啟 Eureka 安全認證 4 spring.security.user.name=root :安全認證用戶名 5 spring.security.user.password=123456 :安全認證密碼
3、Eureka Client 配置
1 eureka.client.registry-fetch-interval-seconds=30 :客戶端獲取服務注冊信息時間間隔,單位 秒。默認 30 2 eureka.instance.appname=eureka-client :服務名,默認取 spring.application.name 配置值,如果沒有則為 unknown 3 eureka.instance.lease-expiration-duration-in-seconds=90 :服務的失效時間,失效的服務將被注冊中心刪除。時間間隔為最后一次注冊中心接收到的心跳時間。單位 秒,默認 90 4 eureka.instance.lease-renewal-interval-in-seconds=30 :應用實例給注冊中心發送心跳的間隔時間,用於表明該服務實例可用。單位 秒。默認30 5 eureka.client.eureka-server-connect-timeout-seconds=5 :client 連接 Eureka 注冊中心的超時時間,單位 秒,默認 5 6 eureka.client.eureka-server-read-timeout-seconds=8 :client 對 Eureka 服務器讀取信息的超時時間,單位 秒,默認 8 7 eureka.client.eureka-connection-idle-timeout-seconds=30 :client 連接 Eureka 服務端后空閑等待時間,單位 秒,默認 30 8 eureka.client.eureka-server-total-connections=200 :client 到 所有Eureka 服務端的連接總數,默認 200 9 eureka.client.eureka-server-total-connections-per-host=50 :client 到 Eureka 單服務端的連接總數,默認 50