從零構建高可用 Eureka 集群 | Spring Cloud 微服務架構深度實踐指南
本文核心內容基于《Spring Cloud 微服務架構開發》第1版整理,結合生產級實踐經驗優化
實驗環境:IntelliJ IDEA 2024 | JDK 1.8| Spring Boot 2.1.7.RELEASE | Spring Cloud Greenwich.SR2項目源碼:本文完整示例代碼已開源至 GitHub,建議結合實踐閱讀
🔗 https://github.com/hongmengchen/spring-cloud-eureka-ha-demo
前言:為什么需要高可用Eureka集群?
在微服務架構中,注冊中心是服務發現與治理的核心樞紐。單節點Eureka Server存在單點故障風險,一旦宕機將導致整個系統服務發現失效。高可用集群通過多節點互備,實現服務注冊表同步與故障自動轉移,保障系統99.99%的可用性。
本文是《從零到一!Spring Cloud Eureka 微服務注冊中心手把手搭建指南》的進階篇,將帶領讀者完成以下目標:
- 集群架構設計:基于CAP理論(一致性、可用性、分區容錯性)選擇AP模式,確保網絡波動時仍可提供服務發現。
- 實戰搭建:通過雙節點互注冊實現數據同步,結合Hosts配置模擬多服務器環境。
- 全鏈路改造:覆蓋服務提供者、消費者的集群適配,并驗證故障切換能力。
實施路線圖
基本流程:
- 系統環境準備(Hosts配置)
- Eureka Server 雙節點改造
- 服務提供者集群適配
- 改造服務消費者
- 測試運行
1. 系統環境準備(Hosts配置)
作用:通過域名映射實現本地多節點模擬
以 Windows 系統為例,如果要構建集群,需要修改 hosts 文件,為其添加主機名的映射。
Windows系統操作指南:
- 以管理員身份運行記事本
- 打開
C:\Windows\System32\drivers\etc\hosts
- 添加以下映射規則:
# Eureka 集群節點映射
127.0.0.1 server1 # 主節點域名
127.0.0.1 server2 # 備用節點域名
在修改 hosts 文件時,部分同學可能會遇到無法修改的問題,我另寫了一篇博客以解決大家的問題:Windows 系統 hosts 文件無法保存?三步搞定權限設置!
建議:大家在修改 hosts 文件權限之后,建議使用完再改會來,也是為了安全考慮嗷
關鍵驗證命令:
ping server1 # 應返回127.0.0.1
ping server2 # 應返回127.0.0.1
2. Eureka Server 雙節點改造
核心邏輯:節點間互相注冊形成環形依賴
按照搭建 eureka-server 的方式,再搭建一個名為 eureka-server-another 的 Eureka Server。
eureka-server-another 的 application.yml 配置文件內容如下:
節點2配置(server2:7009)
server:port: 7009
spring:application:name: eurake-server-another
eureka:client:fetch-registry: falseregister-with-eureka: falseservice-url:defaultZone: http://server1:7000/eureka/ # 指向節點1instance:hostname: server2 # 必須與Hosts配置一致
創建項目每次都差不多
接下來就是補齊這個初創項目的框架
- 補充 pom.xml
- 添加目錄結構
- 完善配置文件 application.yml
- 寫上啟動類
- eureka-server-another 和 eureka-server 一樣都是 Eureka Server,因此 pom.xml 文件內容也是一樣的,大家復制粘貼過來就行,記得點擊更新
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><!-- 父項目 --><parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>2.1.7.RELEASE</version><relativePath/></parent><!-- 基本信息 --><groupId>cn.hmck</groupId><artifactId>eureka-server-another</artifactId><version>1.0-SNAPSHOT</version><!-- 屬性 --><properties><!-- jdk版本 --><java.version>1.8</java.version><!-- spring-cloud版本 --><spring-cloud.version>Greenwich.SR2</spring-cloud.version><maven.compiler.source>8</maven.compiler.source><maven.compiler.target>8</maven.compiler.target><project.build.sourceEncoding>UTF-8</project.build.sourceEncoding></properties><!-- 依賴 --><dependencies><!-- spring-boot-starter --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter</artifactId></dependency><!-- spring-boot-starter-test --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope></dependency><!-- spring-cloud-starter-netflix-eureka-server --><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-netflix-eureka-server</artifactId></dependency></dependencies><!-- spring-cloud依賴管理 --><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><!-- 構建 --><build><plugins><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId></plugin></plugins></build></project>
- 添加目錄結構和之前也是一樣的
- 接著就是補充 application.yml 配置文件
- 最后就是寫上啟動類 EurekaServerApplication.java
新項目的啟動類命名與之前一樣或者不一樣都可以
注意:啟動類外層必須加上一個包名,否則會報錯無法運行,這也是 Spring Cloud 默認規則
這部分代碼和之前依然沒什么區別,可以直接復制粘貼
package cn.hmck.eurekaserveranother;import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer;@EnableEurekaServer
@SpringBootApplication
public class EurekaServerApplication {public static void main(String[] args) {SpringApplication.run(EurekaServerApplication.class, args);}}
修改項目 eureka-server 的全局配置文件 application.yml。
注意哦!這里是指修改一開始的 eureka-server 項目
eureka-server 的 application.yml 配置文件內容如下:
節點1配置(server1:7000)
server:port: 7000
spring:application:name: eurake-server
eureka:client:fetch-registry: falseregister-with-eureka: falseservice-url:defaultZone: http://server2:7009/eureka/ # 指向節點2instance:hostname: server1 # 必須與Hosts配置一致
關鍵配置解析:
fetch-registry: false
:Server節點不獲取注冊表(僅Client需要)register-with-eureka: false
:Server節點不自我注冊- 必須保證:集群節點使用相同的
spring.application.name
簡單解釋一下
3. 服務提供者集群適配
目標:實現服務多實例注冊與負載均衡
按照搭建 eureka-provider 的方式,搭建一個名為 eureka-provider-another 的服務提供者。
eureka-provider-another 的 application.yml 配置文件內容如下:
server:port: 7007
spring:application:name: eureka-provider
eureka:client:service-url:defaultZone: http://localhost:7000/eureka/instance:hostname: localhost
為了體現集群,所以我們還需要再搭建一個服務提供者 eureka-provider-another,流程和前面搭建第二個服務器是一樣的。并且主要代碼和原來的服務提供者 eureka-provider 是一樣的。
- 創建項目 eureka-provider-another
- 補充目錄結構、配置文件及啟動類
- 創建項目 eureka-provider-another
- 補充目錄結構、配置文件及啟動類
pom.xml 文件代碼
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><!-- 父項目 --><parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>2.1.7.RELEASE</version><relativePath/></parent><!-- 基本信息 --><groupId>cn.hmck</groupId><artifactId>eureka-provider-another</artifactId><version>1.0-SNAPSHOT</version><!-- 屬性 --><properties><!-- jdk版本 --><java.version>1.8</java.version><!-- spring-cloud版本 --><spring-cloud.version>Greenwich.SR2</spring-cloud.version><maven.compiler.source>8</maven.compiler.source><maven.compiler.target>8</maven.compiler.target><project.build.sourceEncoding>UTF-8</project.build.sourceEncoding></properties><!-- 依賴 --><dependencies><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-netflix-eureka-client</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><version>2.1.7.RELEASE</version><scope>test</scope></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId><version>2.1.7.RELEASE</version></dependency></dependencies><!-- spring-cloud依賴管理 --><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><!-- 構建 --><build><plugins><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId></plugin></plugins></build>
</project>
啟動類 EurekaProviderApplication.java 代碼
package cn.hmck.eurekaprovider;import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;@SpringBootApplication
@EnableEurekaClient
public class EurekaProviderApplication {public static void main(String[] args) {SpringApplication.run(EurekaProviderApplication.class, args);}
}
最終結果展示
4. 改造服務消費者
核心能力:自動故障轉移與請求重試
修改項目 eureka-consumer 中的全局配置文件 application.yml。
作為消費者的 eureka-consumer ,我們并沒有添加其他的,也沒有對其進行修改,代碼未作變動。
eureka-consumer 的 application.yml 配置文件內容如下:
server:port: 7002
spring:application: name: eureka-consumer
eureka:client:service-url:defaultZone: http://localhost:7000/eurekainstance:hostname: localhost
5. 啟動測試
依次啟動兩個 Eureka Server、兩個服務提供者、一個服務消費者。啟動成功后,無論訪問哪個 Eureka Server,Eureka Server 的注冊實例都是一樣的,訪問 server1:7000 的頁面效果如下圖所示。
訪問server2:7009的頁面效果如下圖所示。
Eureka 的常用配置
1. 心跳機制
Eureka 的心跳機制用于客戶端(服務提供者)與 Eureka Server 之間的健康狀態維護。通過心跳,客戶端定期向 Server 發送信號以表明自身存活狀態,避免被 Server 自動剔除。
核心配置參數
在服務提供者的 application.yml
中配置以下參數:
eureka:instance:# 心跳間隔時間(默認30秒)lease-renewal-interval-in-seconds: 30# 心跳超時時間(默認90秒)lease-expiration-duration-in-seconds: 90
- lease-renewal-interval-in-seconds:客戶端每隔多少秒向 Eureka Server 發送一次心跳。
- lease-expiration-duration-in-seconds:如果 Server 在此時間內未收到心跳,則認為實例不可用并剔除注冊信息。
工作原理
- 客戶端啟動后向 Server 注冊,并開始周期性發送心跳。
- Server 接收到心跳后會重置該實例的租約時間。
- 若 Server 在
lease-expiration-duration-in-seconds
內未收到心跳,則標記實例為DOWN
并從注冊表中移除。
2. 自我保護機制
Eureka Server 的自我保護機制旨在應對網絡分區故障場景。當短時間內丟失大量客戶端心跳時,Server 會進入保護模式,保留現有注冊信息,避免因網絡抖動導致服務被誤刪。
核心配置參數
在 Eureka Server 的 application.yml
中配置以下參數:
eureka:server:# 啟用自我保護機制(默認true)enable-self-preservation: true# 觸發保護模式的閾值(默認0.85,即85%心跳丟失)renewal-percent-threshold: 0.85
- enable-self-preservation:是否啟用自我保護機制,生產環境建議保持
true
。 - renewal-percent-threshold:觸發保護模式的心跳丟失比例閾值(例如 0.85 表示 85% 的心跳未更新時觸發)。
工作機制
- Server 每分鐘統計心跳續約失敗的比例。
- 若失敗比例超過
renewal-percent-threshold
,則進入保護模式:- 不再剔除任何實例(即使心跳超時)。
- 在 Eureka 控制臺顯示警告信息:
EMERGENCY! EUREKA MAY BE INCORRECTLY CLAIMING INSTANCES ARE UP...
- 當心跳恢復正常后,Server 會自動退出保護模式。
配置建議
- 開發環境:可關閉自我保護機制(
enable-self-preservation: false
),方便快速發現失效實例。 - 生產環境:務必啟用自我保護機制,避免因網絡波動導致服務列表頻繁變更。
- 調試技巧:若發現實例未被剔除,需檢查是否因保護模式觸發導致,可通過日志或控制臺提示確認。
特別說明
本次技術實踐文檔的整理與驗證,部分配置優化方案通過 DeepSeek 的智能輔助工具實現效能提升,在此對技術伙伴的支持表示感謝。
技術無界,協作共生
DeepSeek 智能開發平臺
📣 我是鴻·蒙,若有不解之處或發現疏漏,歡迎隨時私信交流!
(雖然不一定秒回,但每條消息都會認真看嗷~ (??????)??)