《Spring Cloud Eureka 高可用集群实战:从零构建 99.99% 可靠性的微服务注册中心》

从零构建高可用 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 微服务注册中心手把手搭建指南》的进阶篇,将带领读者完成以下目标:

  1. 集群架构设计:基于CAP理论(一致性、可用性、分区容错性)选择AP模式,确保网络波动时仍可提供服务发现。
  2. 实战搭建:通过双节点互注册实现数据同步,结合Hosts配置模拟多服务器环境。
  3. 全链路改造:覆盖服务提供者、消费者的集群适配,并验证故障切换能力。

实施路线图

基本流程:

  1. 系统环境准备(Hosts配置)
  2. Eureka Server 双节点改造
  3. 服务提供者集群适配
  4. 改造服务消费者
  5. 测试运行

1. 系统环境准备(Hosts配置)

作用:通过域名映射实现本地多节点模拟

以 Windows 系统为例,如果要构建集群,需要修改 hosts 文件,为其添加主机名的映射。

Windows系统操作指南

  1. 以管理员身份运行记事本

  2. 打开 C:\Windows\System32\drivers\etc\hosts

  3. 添加以下映射规则:

    Eureka 集群节点映射

    127.0.0.1 server1 # 主节点域名
    127.0.0.1 server2 # 备用节点域名

在修改 hosts 文件时,部分同学可能会遇到无法修改的问题,我另写了一篇博客以解决大家的问题:Windows 系统 hosts 文件无法保存?三步搞定权限设置!

建议:大家在修改 hosts 文件权限之后,建议使用完再改会来,也是为了安全考虑嗷

关键验证命令

bash 复制代码
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)

yml 复制代码
server:
    port: 7009
spring:
    application:
         name: eurake-server-another
eureka:
    client:
       fetch-registry: false
       register-with-eureka: false
       service-url:
           defaultZone: http://server1:7000/eureka/  # 指向节点1
    instance:
       hostname: server2 # 必须与Hosts配置一致

创建项目每次都差不多

接下来就是补齐这个初创项目的框架

  1. 补充 pom.xml
  2. 添加目录结构
  3. 完善配置文件 application.yml
  4. 写上启动类
  1. eureka-server-another 和 eureka-server 一样都是 Eureka Server,因此 pom.xml 文件内容也是一样的,大家复制粘贴过来就行,记得点击更新
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>
  1. 添加目录结构和之前也是一样的
  1. 接着就是补充 application.yml 配置文件
  1. 最后就是写上启动类 EurekaServerApplication.java

新项目的启动类命名与之前一样或者不一样都可以

注意:启动类外层必须加上一个包名,否则会报错无法运行,这也是 Spring Cloud 默认规则

这部分代码和之前依然没什么区别,可以直接复制粘贴

java 复制代码
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)

yml 复制代码
server:
    port: 7000
spring:
    application:
         name: eurake-server
eureka:
    client:
       fetch-registry: false
       register-with-eureka: false
       service-url:
           defaultZone: http://server2:7009/eureka/  # 指向节点2
    instance:
       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 配置文件内容如下:

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 是一样的。

  1. 创建项目 eureka-provider-another
  2. 补充目录结构、配置文件及启动类
  1. 创建项目 eureka-provider-another
  1. 补充目录结构、配置文件及启动类

pom.xml 文件代码

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 代码

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 配置文件内容如下:

yml 复制代码
server:
	port: 7002  
spring:
	application:  
	   name: eureka-consumer	
eureka:
    client:
	   service-url:
		defaultZone: http://localhost:7000/eureka
  instance:
      hostname: localhost

5. 启动测试

依次启动两个 Eureka Server、两个服务提供者、一个服务消费者。启动成功后,无论访问哪个 Eureka Server,Eureka Server 的注册实例都是一样的,访问 server1:7000 的页面效果如下图所示。

访问server2:7009的页面效果如下图所示。


Eureka 的常用配置

1. 心跳机制

Eureka 的心跳机制用于客户端(服务提供者)与 Eureka Server 之间的健康状态维护。通过心跳,客户端定期向 Server 发送信号以表明自身存活状态,避免被 Server 自动剔除。

核心配置参数

在服务提供者的 application.yml 中配置以下参数:

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 在此时间内未收到心跳,则认为实例不可用并剔除注册信息。

工作原理

  1. 客户端启动后向 Server 注册,并开始周期性发送心跳。
  2. Server 接收到心跳后会重置该实例的租约时间。
  3. 若 Server 在 lease-expiration-duration-in-seconds 内未收到心跳,则标记实例为 DOWN 并从注册表中移除。

2. 自我保护机制

Eureka Server 的自我保护机制旨在应对网络分区故障场景。当短时间内丢失大量客户端心跳时,Server 会进入保护模式,保留现有注册信息,避免因网络抖动导致服务被误删。

核心配置参数

在 Eureka Server 的 application.yml 中配置以下参数:

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% 的心跳未更新时触发)。

工作机制

  1. Server 每分钟统计心跳续约失败的比例。
  2. 若失败比例超过 renewal-percent-threshold,则进入保护模式:
    • 不再剔除任何实例(即使心跳超时)。
    • 在 Eureka 控制台显示警告信息:EMERGENCY! EUREKA MAY BE INCORRECTLY CLAIMING INSTANCES ARE UP...
  3. 当心跳恢复正常后,Server 会自动退出保护模式。

配置建议

  • 开发环境 :可关闭自我保护机制(enable-self-preservation: false),方便快速发现失效实例。
  • 生产环境:务必启用自我保护机制,避免因网络波动导致服务列表频繁变更。
  • 调试技巧:若发现实例未被剔除,需检查是否因保护模式触发导致,可通过日志或控制台提示确认。

特别说明

本次技术实践文档的整理与验证,部分配置优化方案通过 DeepSeek 的智能辅助工具实现效能提升,在此对技术伙伴的支持表示感谢。

技术无界,协作共生

点击访问:DeepSeek 智能开发平台


📣 我是鸿·蒙,若有不解之处或发现疏漏,欢迎随时私信交流!

(虽然不一定秒回,但每条消息都会认真看嗷~ (๑•̀ㅂ•́)و✧)

相关推荐
chanalbert3 小时前
SpringBoot设计基石:约定优于配置与模块化架构
spring boot·spring·spring cloud
RexTechie1 天前
Spring Cloud Alibaba 中间件
java·spring cloud·中间件
RexTechie1 天前
Spring Cloud 原生中间件
spring·spring cloud·中间件
码不停蹄的玄黓2 天前
JUC核心解析系列(五)——执行框架(Executor Framework)深度解析
java·jvm·spring boot·spring cloud
蓝色天空的银码星3 天前
SpringCloud微服务架构下的日志可观测解决方案(EFK搭建)
spring cloud·微服务·架构
.生产的驴3 天前
SpringBoot 服务器监控 监控系统开销 获取服务器系统的信息用户信息 运行信息 保持稳定
服务器·spring boot·分布式·后端·spring·spring cloud·信息可视化
hqxstudying3 天前
Kafka
java·spring cloud·kafka
康小庄3 天前
AQS独占模式——资源获取和释放源码分析
java·开发语言·jvm·spring boot·spring·spring cloud·nio
码不停蹄的玄黓3 天前
通关JUC:Java并发工具包从入门到精通 | 深度源码解析
java·jvm·spring boot·spring·spring cloud
异常君3 天前
Dubbo 与 Spring Cloud Gateway 技术对比:微服务架构中的协同实践
spring cloud·微服务·dubbo