找回密码
立即注册
搜索
热搜: Java Python Linux Go
发回帖 发新帖

1352

积分

0

好友

172

主题
发表于 昨天 04:58 | 查看: 5| 回复: 0

在构建微服务体系时,服务治理是协调各服务实例、保障系统稳定运行的关键一环。Spring Cloud 生态中,服务治理与发现功能常通过 Netflix Eureka 实现。为了让开发者能够更便捷地使用,Pivotal 团队将其封装为 Spring Cloud Netflix Eureka 项目。下面我们通过一个具体的项目实例,来拆解服务治理与服务发现的实现过程。

首先,我们需要创建一个包含多个模块的 Spring Boot 项目来模拟微服务环境。项目结构包含 eureka-server(治理中心)、customergoods(业务服务)等模块。

Spring Cloud多模块项目pom.xml配置截图
IntelliJ IDEA中Spring Cloud项目的模块与依赖配置
IntelliJ IDEA中Web应用Artifacts配置界面

搭建服务治理中心 - Eureka Server

治理中心是整个微服务架构的“大脑”。我们首先在 eureka-server 模块中引入必要的依赖。由于 Eureka Server 本身是一个 Web 应用,所以也需要引入 Web 启动器。

        <!-- 引入Spring Boot的Webstarter依赖,它为构建Web应用程序提供了必需的组件,包括Servlet容器和Spring Web MVC。 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <!-- 引入Spring Cloud的Eureka Server starter依赖,用于实现服务注册与发现的功能。 -->
        <!-- 它基于Netflix Eureka,提供了微服务架构中服务之间互相发现和通信的能力。 -->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
        </dependency>

接下来,修改 eureka-server 模块的启动类,使用 @EnableEurekaServer 注解来启用 Eureka 服务端功能。

package com.scd.eurekaserver;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer;

/**
 * Eureka Server应用程序入口类。
 * 使用@SpringBootApplication注解标记这是一个Spring Boot应用程序,
 * 同时通过@EnableEurekaServer注解启用Eureka Server功能,使得当前应用程序成为一个Eureka注册中心。
 */
@SpringBootApplication
@EnableEurekaServer
public class EurekaServerApplication {
    /**
     * 程序入口方法。
     * 使用SpringApplication.run方法启动Spring Boot应用程序,
     * 参数为当前类和应用程序启动参数。
     *
     * @param args 应用程序启动参数
     */
    public static void main(String[] args) {
        SpringApplication.run(EurekaServerApplication.class, args);
    }
}

Eureka Server启动类代码截图

然后,在 eureka-server 模块的配置文件(如 application.yml)中添加核心配置:

# 定义Spring应用名称,它是一个服务的名称,一个服务可拥有多个实例
spring:
  application:
    name:  eureka-server
# 启动端口
server:
  port: 1001
eureka:
  client:
    # 服务自身就是治理中心,所以这里设置为false,取消注册
    register-with-eureka: false
    # 取消服务获取,至于服务获取,后续会进行讨论
    fetch-registry: false
  instance:
    # 服务治理中心服务器IP
    hostname: 192.168.3.115

配置完成后,启动 eureka-server 模块。

Eureka Server运行配置截图

通过浏览器访问 http://localhost:1001/,即可看到 Eureka Server 的管理界面,此时还没有任何服务注册上来。

初始状态下空的Eureka服务治理中心页面

实现服务发现

Eureka 服务治理中心本身不会主动去“扫描”网络中的服务。服务发现的过程是由各个服务实例(客户端)主动向治理中心发送 REST 请求来完成的,主要包括注册、续约和下线等操作。接下来,我们将 customergoods 模块注册到 Eureka。

首先,在这两个业务服务模块中引入 Eureka 客户端依赖。

        <!-- 引入Eureka客户端依赖,用于实现服务发现功能 -->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
        </dependency>

你可以将 Eureka 治理中心视为服务端,而引入 eureka-client 依赖的模块就是客户端。客户端启动后,会自动通过 REST 请求与配置的服务端地址建立联系。

接着,分别修改这两个模块的配置文件。这里以 customer 模块为例,goods 模块配置类似。

customer 服务配置 (application.yml):

# Spring应用名称(服务名称)
spring:
  application:
    name: customer
# 请求URL,指向Eureka服务治理中心
eureka:
  client:
    serviceUrl:
      defaultZone: http://localhost:1001/eureka/
  instance:
    # 服务实例主机
    hostname: 192.168.3.115
# 服务端口
server:
  port: 3001

goods 服务配置 (application.yml):

# Spring应用名称(服务名称)
spring:
  application:
    name: goods
# 请求URL,指向Eureka服务治理中心
eureka:
  client:
    serviceUrl:
      defaultZone: http://localhost:1001/eureka/
  instance:
    # 服务实例主机
    hostname: 192.168.3.115
# 服务端口
server:
  port: 2001

在旧版本的 Spring Cloud 中,可能还需要在启动类上添加 @EnableEurekaClient 注解。但在新版本中,只要引入了 spring-cloud-starter-netflix-eureka-client 依赖,就会自动启用客户端功能,无需修改任何代码。

依次启动 goodscustomer 模块,等待大约 30 秒后,再次访问 http://localhost:1001/,可以看到两个服务已经成功注册。

注册了CUSTOMER和GOODS服务实例的Eureka页面

页面上出现的红色警告是 Eureka Server 的自我保护机制。当它监测到短时间内有过多服务实例下线时,会触发此机制以防止因网络波动误删健康实例。如果是在开发环境想关闭它,可以在 Eureka Server 的配置中设置:

# 定义Spring应用名称,它是一个服务的名称,一个服务可拥有多个实例
spring:
  application:
    name:  eureka-server
# 启动端口
server:
  port: 1001
eureka:
  # 服务器配置段,用于定义服务器的行为和特性
  server:
    # 是否启用自我保护模式
    # 自我保护模式是一种机制,用于在服务器负载过高时自动限制某些操作,以保护服务器免于崩溃
    enable-self-preservation: false
  client:
    # 服务自身就是治理中心,所以这里设置为false,取消注册
    register-with-eureka: false
    # 取消服务获取,至于服务获取,后续会进行讨论
    fetch-registry: false
  instance:
    # 服务治理中心服务器IP
    hostname: 192.168.3.115

构建高可用架构

在实际生产环境中,单一的服务实例或单一的服务治理中心都存在单点故障风险。因此,我们需要构建高可用架构:一个服务可以有多个实例,服务治理中心本身也可以有多个节点。

首先,我们利用 IDEA 的“运行配置”功能,为同一个服务启动多个不同端口的实例。以 eureka-server 为例,我们可以在配置中覆盖 server.port 参数。

在IDEA运行配置中覆盖Eureka Server端口为1001

复制一份运行配置,并将端口改为 1002,这样我们就有了两个 Eureka Server 实例的启动配置。

复制Eureka Server运行配置并将端口改为1002

配置第二个Eureka Server实例端口为1002的详细界面

用同样的方法,为 customergoods 服务也各创建两个运行实例,端口分别为 3001/3002 和 2001/2002。

配置Customer服务第一个实例端口为3001
配置Customer服务第二个实例端口为3002
配置Goods服务第一个实例端口为2001
配置Goods服务第二个实例端口为2002

这样配置后,server.port 会作为命令行参数传入,覆盖 application.yml 文件中的端口设置。但这还不够,我们需要修改服务治理中心和各服务的配置,让它们知道彼此的存在,并能够相互注册。

修改 eureka-server 的配置文件,关键点在于 eureka.client.serviceUrl.defaultZone 需要指向另一个 Eureka Server 节点,让它们互相注册。

# 定义Spring应用名称,它是一个服务的名称,一个服务可拥有多个实例
spring:
  application:
    name:  eureka-server
# 启动端口
# server:
#   port: 1001
eureka:
  # 服务器配置段,用于定义服务器的行为和特性
  server:
    # 是否启用自我保护模式
    # 自我保护模式是一种机制,用于在服务器负载过高时自动限制某些操作,以保护服务器免于崩溃
    enable-self-preservation: false
  client:
    # 服务自身就是治理中心,所以这里设置为false,取消注册
    register-with-eureka: false
    # 取消服务获取,至于服务获取,后续会进行讨论
    fetch-registry: false
    serviceUrl:
      # Eureka服务端相互注册
      defaultZone: http://localhost:1001/eureka/,http://localhost:1002/eureka/
  instance:
    # 服务治理中心服务器IP
    hostname: 192.168.3.115

同时,修改 customergoods 服务的配置,让它们的 defaultZone 同时指向这两个 Eureka Server,实现客户端的服务发现负载均衡与容错。

goods 服务配置更新:

# Spring应用名称(服务名称)
spring:
  application:
    name: goods
# 请求URL,指向Eureka服务治理中心
eureka:
  client:
    serviceUrl:
      defaultZone: http://localhost:1001/eureka/,http://localhost:1002/eureka/
  instance:
    # 服务实例主机
    hostname: 192.168.3.115
# 服务端口
server:
  port: 2001

customer 服务配置更新:

# Spring应用名称(服务名称)
spring:
  application:
    name: customer
# 请求URL,指向Eureka服务治理中心
eureka:
  client:
    serviceUrl:
      defaultZone: http://localhost:1001/eureka/,http://localhost:1002/eureka/
  instance:
    # 服务实例主机
    hostname: 192.168.3.115
# 服务端口
server:
  port: 3001

重新启动所有模块后,查看控制台日志,确认服务注册成功。

多个服务实例启动时的控制台日志输出

此时分别访问 http://localhost:1001/http://localhost:1002/,可以看到两个 Eureka Server 页面上都显示了相同的、完整的服务实例列表。这意味着即使其中一个治理中心节点宕机,另一个节点依然能提供服务注册与发现的能力,从而实现了高可用。

两个Eureka Server节点页面,均显示完整的CUSTOMER和GOODS服务实例

这样就初步实现了服务的高可用。注册到治理中心的服务实例,如果被治理中心判断为已挂掉,会被自动剔除。但前提是治理中心本身不能挂掉。为了让多个 Eureka Server 节点之间也能互相感知状态,需要将它们的 register-with-eureka 设置为 true(在上面的配置中我们为了简化先设为 false,实际高可用集群需要设为 true 并相互注册)。重启后,它们会互相注册为服务实例,形成一个对等的集群,任何一个节点宕机都不会影响整体功能。

两个Eureka Server节点互相注册后的高可用集群状态页面

Eureka 工作原理剖析

整个 Eureka 的运作机制可以概括为下图所示的流程:

Eureka服务注册、发现与续约工作机制架构图

Eureka 的服务端与客户端之间,是由客户端主动发送 REST 请求来完成交互的。请求的地址正是通过配置项 eureka.client.serviceUrl.defaultZone 生成的。多个 Eureka Server 节点之间是对等(Peer-to-Peer)关系,数据通过异步复制保持最终一致性。

  • 服务注册:一个服务实例想要被治理中心发现,必须先进行注册。客户端将自身信息(如主机、端口、健康状态等)通过 REST 请求发送给治理中心。这里的关键配置是 spring.application.name,Eureka 用它来区分服务类型,相同名称的实例被认为是同一服务的不同副本。注册并非在服务启动后立即发生,默认有 40 秒的延迟,可通过 eureka.client.initial-instance-info-replication-interval-seconds 调整。
  • 服务续约:服务实例启动后,可能因故障或下线而变得不可用。为了监控实例健康状态,Eureka 要求客户端实例定期(默认每30秒)发送心跳请求进行续约,以告知治理中心自己仍然存活。如果治理中心在一段时间内(默认90秒)未收到某个实例的续约,则会认为该实例已失效并将其从注册表中剔除。这两个时间可以通过 eureka.instance.lease-renewal-interval-in-secondseureka.instance.lease-expiration-duration-in-seconds 配置。
  • 服务下线:当一个服务实例需要正常关闭时,它会主动向 Eureka Server 发送一个下线请求。治理中心收到请求后,会立即将该实例从注册表中移除,这是一个优雅的注销过程。

通过以上步骤,Eureka 实现了微服务架构中动态的服务治理与发现。虽然现在有更多云原生的选择,但理解 Eureka 的基本原理对于掌握Spring Boot微服务架构的基石仍然至关重要。在实践中,根据业务规模选择合适的服务发现组件,并合理配置参数,是构建稳定可靠的分布式系统的关键。如果你想探讨更多关于微服务架构或云原生技术的话题,欢迎在云栈社区交流分享。




上一篇:Williams %R与QStick量化策略:Python实现20年回测,收益率4644%
下一篇:MyBatis 插件机制深度解析:零侵入扩展 Executor/StatementHandler 实战指南(3.4+)
您需要登录后才可以回帖 登录 | 立即注册

手机版|小黑屋|网站地图|云栈社区 ( 苏ICP备2022046150号-2 )

GMT+8, 2026-2-23 12:57 , Processed in 0.597186 second(s), 41 queries , Gzip On.

Powered by Discuz! X3.5

© 2025-2026 云栈社区.

快速回复 返回顶部 返回列表