前言
參考資料:
《Spring Microservices in Action》
《Spring Cloud Alibaba 微服務原理與實戰》
《B站 尚矽谷 SpringCloud 框架開發教程 周陽》
《Spring Cloud Netflix 官方資料》
Eureka 是 Netflix 開發的服務發現框架,本身是一個基於REST的服務,主要用於定位執行在 AWS 域中的中間層服務,以達到負載均衡和中間層服務故障轉移的目的;
Spring Cloud 將它整合在其子專案 spring-cloud-netflix 中,以實現 Spring Cloud 的服務發現功能;
1. Eureka 基礎知識
1.1 Eureka 模型中的伺服器與客戶端
- 伺服器:服務的註冊中心,負責維護與管理註冊的服務列表;
- 客戶端:所有要註冊進 Eureka 的服務都稱為 Eureka 的客戶端,它可以是服務配置中心 Spring Cloud Config;也可以是閘道器 zuul;還可以是實際的業務服務等;
1.2 Eureka 的 30s 啟動機制
- 當客戶端服務通過 Eureka 註冊時, Eureka 將在 30s 內等待 3 次連續的健康檢查,然後才能通過 Eureka 獲取該服務;
- 每次服務註冊需要 30 s 的時間才能顯示在 Eureka服務中,因為 Eureka需要從服務接收 3 次。連續心跳包 ping,每次心跳包 ping 間隔 10 s,然後才能使用這個服務;
1.3 Eureka 為什麼註冊服務的 IP ,而不是主機名
- 具體例子詳情可以參考《3.2 修改 boostrap.yml 配置檔案》;
- 在基於伺服器的環境中時:Eureka 在嘗試註冊客戶端服務時,客戶端服務會被分配一個 DNS 支援的主機名,客戶端服務通過這個 DNS 主機名與外界聯絡;
- 在基於容器的部署(如 Docker)中:容器以隨機生成的主機名啟動,沒有 DNS 記錄;使用主機名將無法解析;
1.4 Eureka 伺服器的高可用(叢集)
- 在實際生產中,為了實現 Eureka 的高可用,需要建立多個 Eureka 伺服器以便相互複製登錄檔的內容;
- 一組 Eureka 登錄檔相互之間使用點對點通訊模型進行通訊;
- 需要在客戶端
eureka.serviceUrl.defaultZone
屬性中用逗號隔開多個 Eureka 伺服器的位置; - 同時,伺服器的
eureka.serviceUrl.defaultZone
屬性中用逗號隔開多個除了自身的 Eureka 伺服器的位置;
2. 構建 Eureka 伺服器
2.1 引入 pom.xml 依賴
<!-- 1.x老版本的依賴 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-eureka-server</artifactId>
</dependency>
<!-- 2.x新版本的依賴 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
</dependency>
- Eureka 的 Maven 依賴檔案預設包含 Ribbon 元件;
- 新老版本二選一即可;
2.2 修改 application.yaml 配置檔案
server:
port: 8761 #Eureka 監聽的埠
spring:
application:
name: eureka-server #Eureka 伺服器的名稱
eureka:
client:
fetch-registry: false #不要在本地快取登錄檔資訊
register-with-eureka: false #不使用 Eureka 服務進行註冊
serviceUrl:
defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/
instance:
hostname: localhost
server: #配置屬性,但由於 Eureka 自我保護模式以及心跳週期長的原因,經常會遇到 Eureka Server 不剔除已關停的節點的問題
enable-self-preservation: false
eviction-interval-timer-in-ms: 5000
waitTimelnMsWhenSyncEmpty: 5 #在伺服器接收請求之前等待的初始時間,在實際生產中應註釋掉此屬性
- 如果需要將元件註冊進 Eureka 裡,需要把
eureka.client.register-with-eureka
置為 true,或者不管它,使用預設值 true; - 只有 Eureka 的客戶端才需要把
eureka.client.register-with-eureka
置為 true;
2.3 在主程式類上標註註解
@EnableEurekaServer:表示該服務為 Eureka 伺服器;
3. 將客戶端註冊進 Eureka 伺服器
3.1 引入 pom.xml 依賴
<!--註冊中心-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-eureka</artifactId>
</dependency>
- 因為每個服務基本上都會註冊進 Eureka 伺服器裡,因此該依賴可以新增到父工程裡,表示公共依賴;
3.2 修改 boostrap.yml 配置檔案
spring:
application:
name: xxx-client #應用程式ID,常寫在 boostrap.yml 下
profiles:
active: dev
cloud:
config:
enabled: true
eureka:
instance:
preferIpAddress: true #註冊服務的IP,而不是服務名稱
client:
registerWithEureka: true #向 Eureka 註冊服務
fetchRegistry: true #拉取登錄檔的本地副本
serviceUrl:
defaultZone: http://localhost:8761/eureka/ #Eureka 服務模組
- 每個通過 Eureka 註冊的服務都會有兩個與之相關的 ID:
- 應用程式 ID:表示一組服務實,D始終是由
spring.application.name
屬性設定的值(寫在 bootstrap.yml 配置檔案中,而不是 application.xml); - 例項 ID:一個隨機數,用於代表單個服務例項;
- 應用程式 ID:表示一組服務實,D始終是由
- 為什麼註冊服務的 IP ,而不是主機名:
- 在基於伺服器的環境中時:Eureka 在嘗試註冊客戶端服務時,客戶端服務會被分配一個 DNS 支援的主機名,客戶端服務通過這個 DNS 主機名與外界聯絡;
- 在基於容器的部署(如 Docker)中:容器以隨機生成的主機名啟動,沒有 DNS 記錄;使用主機名將無法解析;
3.3 在主程式類上標註服務發現的註解
- @EnableEurekaClient:推薦使用 Eureka 作為註冊中心;
- @EnableDiscoveryClient:推薦使用其他元件作為註冊中心;
4. Eureka Server 的自我保護
4.1 故障現象
- 如果在Eureka Server的首頁看到以下這段提示,則說明Eureka進入了保護模式:
- Eureka Server 一旦進入自我保護模式,將會嘗試保護其服務登錄檔中的資訊,不再刪除服務登錄檔中的資料,也不會登出任何微服務;
4.2 自我保護概述
- 保護模式主要用於一組客戶端和 Eureka Server 之間存在網路分割槽場景下的保護;
- 為了防止 Eureka Client 可以正常執行,但是與 Eureka Server 網路不通情況下,Eureka Server 不會立刻將 Eureka Client 服務剔除;
4.3 自我保護原理
- 預設情況下,如果 Eureka Server 在一定時間內沒有接收到某個微服務例項的心跳,Eureka Server 將會登出該例項(預設90秒);
- 但是當網路分割槽故障發生(延時、卡頓、擁擠)時,微服務與 Eureka Server 之間無法正常通訊,以上行為可能變得非常危險了;
- 因為微服務本身其實是健康的,此時本不應該登出這個微服務;
- Eureka 通過“自我保護模式”來解決這個問題:當 Eureka Server 節點在短時間內丟失過多客戶端時(可能發生了網路分割槽故障),那麼這個節點就會進入自我保護模式;
- 在自我保護模式中,Eureka Server 會保護服務登錄檔中的資訊,不再登出任何服務例項;
4.4 關閉自我保護機制
- 使用如下配置可以關閉自我保護機制,保證不可用服務被及時踢除:
eureka.server.enable-self-preservation = false
;