目录

Eureka

Eureka

一、原理分析

Eureka 是 Netflix 开源的服务发现组件,基于 REST 实现,主要用于 AWS 云环境中的中间层服务发现与故障转移。其核心原理围绕服务注册、心跳续约、服务剔除和客户端缓存等机制展开。

服务注册机制

服务实例启动时向 Eureka Server 发送 POST 请求注册自身信息,包含主机名、端口、健康检查 URL 等元数据。Eureka Server 将这些信息存储在双层结构的注册表中:

  • 第一层存储服务实例的原始信息(读写频繁)
  • 第二层存储经过压缩优化的只读数据(用于客户端查询)

注册表采用多级缓存设计,包括:

  • 读写缓存(ConcurrentHashMap
  • 只读缓存(定时从读写缓存同步)
  • 客户端本地缓存(定时从服务器拉取)

心跳续约与健康检查

服务实例默认每 30 秒向 Eureka Server 发送心跳(PUT 请求续约)。若 90 秒内未收到续约,服务器将该实例标记为不可用。自我保护模式下,服务器会保留过期的实例注册信息。

健康检查机制分为两种:

  1. 客户端主动上报健康状态(集成 Spring Boot Actuator)
  2. 服务器端主动探测(需配置 eureka.server.healthcheck.enabled=true

服务剔除机制

Eureka Server 默认每 60 秒执行一次清理任务,移除超过 90 秒未续约的实例。自我保护模式触发条件为:

  • 15 分钟内超过 85% 的实例未续约
  • 满足条件时停止剔除实例,直到续约比例恢复正常

剔除算法采用加权随机选择,避免同时剔除大量实例导致服务雪崩。

客户端缓存与负载均衡

Eureka Client 每 30 秒从服务器拉取全量注册表,本地缓存采用双队列结构:

  • 当前使用队列(currentRegistry
  • 备用更新队列(updateRegistry

Ribbon 集成时通过以下步骤实现动态负载均衡:

  1. 从 Eureka Client 获取服务实例列表
  2. 根据策略(轮询、随机等)选择实例
  3. 定期刷新服务器列表(默认 30 秒)

集群同步机制

多节点间采用异步复制保证最终一致性。新注册信息通过 replicateToPeers 方法广播到集群其他节点。同步过程采用 HTTP 批量请求,通过 batching 和 compression 优化网络传输。

二、搭建eureka服务

1.创建一个maven模块

2.引入依赖


 <!--eureka服务端-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
        </dependency>

3.创建一个启动类,并添加@EnableEurekaServer注解


package cn.itcast.eureka;

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


@EnableEurekaServer
@SpringBootApplication
public class EurekaApplication {
    public static void main(String[] args) {
        SpringApplication.run(EurekaApplication.class, args);
    }
}

4.添加配置信息


server:
  port: 10086


spring:
  application:
    name: eurekaserver

eureka:
  client:
    service-url:
      defaultZone: http://localhost:10086/eureka

server 部分:

port: 10086 - 指定 Eureka 服务器运行的端口号为 10086
spring 部分:

application.name: eurekaserver - 设置 Spring 应用名称为 “eurekaserver”,这个名称会在服务注册时使用
eureka 部分:

client.service-url.defaultZone: http://localhost:10086/eureka - 配置 Eureka 客户端(这里服务器本身也作为客户端)注册到的服务器的地址
由于这是 Eureka 服务器的配置,它实际上是配置自己将自己注册为一个服务
defaultZone 是 Eureka 服务的注册中心地址,这里指向本机

三、服务注册

1.引入依赖


    <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
        </dependency>

2.配置文件


spring:
  application:
    name: orderserver   #服务名称


#eureka注册
eureka:
  client:
    service-url:
      defaultZone: http://localhost:10086/eureka    #eureka服务地址

如何查看服务是否注册成功

访问 Eureka 控制台

输入 http://localhost:10086,能看到 Eureka 的管理页面即表示正常

https://i-blog.csdnimg.cn/direct/6e8105bf5f544b3b9482561ae76ed0f3.png

System Status(系统状态)

  • Environment:环境标识,此处为 test,用于区分不同环境(如开发、测试、生产)下的 Eureka 服务。
  • Data center:数据中心,显示为 default,表示使用默认的数据中心配置。
  • Current time:当前时间,即页面加载时的系统时间。
  • Uptime:Eureka 服务启动时长,这里显示 00:01,说明服务刚启动 1 分钟左右。
  • Lease expiration enabled:是否启用租约过期机制,值为 false 表示未启用。租约过期机制用于检测服务实例是否正常,若启用,服务实例需定期发送心跳,否则会被标记为失效。
  • Renews threshold:续约阈值,值为 5,表示 Eureka 服务期望每分钟收到的心跳续约数量阈值。
  • Renews (last min):最近一分钟内收到的心跳续约数量,此处为 0,可能是因为刚启动,还未到服务实例发送心跳的时间,或者暂时没有服务实例注册。

DS Replicas(集群副本)

显示 localhost,表示当前 Eureka 服务为单节点部署,没有集群副本(若为集群部署,这里会列出其他 Eureka 节点的地址)。

Instances currently registered with Eureka(当前注册到 Eureka 的实例)

这部分列出了已注册到 Eureka 的服务实例:

  • EUREKASERVER:服务名称为 EUREKASERVER 的实例,Status 为 UP,表示该实例正常运行,地址为 10.20.3.254:eurekaserver:1008610086 是 Eureka 服务本身的端口)。
  • UNKNOWN:有两个状态为 UP 的实例,地址分别为 10.20.3.254:8081 和 10.20.3.254:8080UNKNOWN 通常是因为服务实例未正确配置应用名称(spring.application.name),导致 Eureka 无法识别具体服务名。

General Info(常规信息)

展示了 Eureka 服务所在服务器的一些基础信息:

  • total-avail-memory:总可用内存,为 108mb
  • environment:环境,与之前的 Environment 一致,为 test
  • num-of-cpus:CPU 核心数,为 16
  • current-memory-usage:当前内存使用量,65mb (60%),表示已使用 65MB,占总可用内存的 60%。
  • server-uptime:服务器运行时长,与之前的 Uptime 一致,为 00:01

我们可以启动多个user-server服务,模拟多实例部署,但为了避免端口冲突,需要修改端口设置:

https://i-blog.csdnimg.cn/direct/a5555535e32d41928aa9776b6cdf715f.png

https://i-blog.csdnimg.cn/direct/dbbc8c58e36e4336a1f690c804e9f642.png

https://i-blog.csdnimg.cn/direct/d2b9eae5e1aa4a72987b17719cf8e2bb.png

若有其他需要区分的配置(如服务名、数据库连接等),也可通过 -D 参数指定:


-Dserver.port=8081 -Dspring.application.name=order-service-2

https://i-blog.csdnimg.cn/direct/4e05d0b71dd34b8a99194be505d3dc12.png

这样就启动了多个实例

四、服务发现

服务拉取是基于服务名称获取服务列表,然后对服务列表做负载均衡

1.修改服务的代码,修改访问的url路径,用服务名代替ip,端口:

https://i-blog.csdnimg.cn/direct/4cc4371c8b3b4ba58d7a834e0453d2cd.png

2.在oder-service项目的启动类OrderApplication中的RestTemplate添加负载均衡注解:

https://i-blog.csdnimg.cn/direct/6c31ebd2c59b45b4b5ee1956059dd804.png

五、Ribbon负载均衡

https://i-blog.csdnimg.cn/direct/50aec64b53c7494299771fb1a07b641b.png

在远程调用时,我们使用@loadBalanced标记了RestTemplate,表示resrTemplate发起的请求要被Ribbon拦截和处理

https://i-blog.csdnimg.cn/direct/8606a26124ac4d6493da3357f580b6d1.png

@LoadBalanced 是 Spring Cloud 中的一个注解,主要用于实现客户端负载均衡。其核心原理基于 Ribbon 或 Spring Cloud LoadBalancer(新版本默认),通过动态选择服务实例来分发请求。

核心工作机制

  1. 服务实例列表动态获取
    通过服务注册中心(如 Eureka、Nacos)获取目标服务的所有可用实例列表,并定期更新。

  2. 负载均衡策略
    默认支持轮询(Round Robin)、随机(Random)、权重(Weighted)等算法,用户可自定义策略。例如:

    
    @Bean
    public IRule loadBalancerRule() {
        return new RandomRule(); // 随机策略
    }
  3. 注解触发拦截器
    在 REST 请求(如 RestTemplate 或 WebClient)被调用时,@LoadBalanced 会触发负载均衡拦截器,将原始服务名(如 http://service-name/api)替换为实际选中的实例地址。

关键组件

  • Ribbon 或 Spring Cloud LoadBalancer
    旧版依赖 Ribbon,新版默认使用 Spring Cloud LoadBalancer,两者均通过 ServiceInstanceListSupplier 获取实例列表。
  • 拦截器链
    LoadBalancerInterceptor 拦截请求,通过 LoadBalancerClient 选择实例并重构请求 URL。

示例代码


@Configuration
public class Config {
    @Bean
    @LoadBalanced // 启用负载均衡
    public RestTemplate restTemplate() {
        return new RestTemplate();
    }
}

// 使用时直接调用服务名
String result = restTemplate.getForObject("http://user-service/info", String.class);

注意事项

  • 若未启用服务发现(如无注册中心),需手动配置实例列表。
  • 新版本中 Ribbon 已进入维护模式,建议迁移至 Spring Cloud LoadBalancer。

https://i-blog.csdnimg.cn/direct/be2c9b267cfb480da0bddfdf810ae5b0.png

负载均衡策略

https://i-blog.csdnimg.cn/direct/8947554feaa14b108bc49450a570b644.png

https://i-blog.csdnimg.cn/direct/0958ed501b4b4e539fa0d98e37cd64e9.png

通过定义IRUle实现可以修改负载均衡规则,有两种方式:

1.代码方式:在order-service中的OrderApplication类中,定义一个新的IRule:


  //配置负载均衡策略,可以自己定义一个配置类
    @Bean
    public IRule rule() {
        return new RandomRule();//随机
    }

2.配置文件方式:在order-service的application.yml文件中,添加新的配置也可以修改规则:


userservice:
  ribbon:
    NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RandomRule

该配置将userservice服务的负载均衡策略设置为随机选择(RandomRule)。当应用通过Ribbon调用userservice时,会从可用的服务实例中随机选择一个实例进行请求分发。

饥饿加载

来看看第一次请求的时间

https://i-blog.csdnimg.cn/direct/0e04fed051b74fa39d4db30137edb879.png

ribbon默认是采用懒加载,即第一次访问时才创建LoadBalanceClient,请求时间会很长。而饥饿加载则会在项目创建时创建,降低第一次访问的耗时,通过下面配置开启饥饿加载:


#  ribbon:
ribbon:
  eager-load:
    enabled: true #开启饥饿加载
    clients: userserver #指定饥饿加载的服务名称
      - userserver #如果有更多的服务需要饥饿加载,换行加杠,写上服务名称 

重新启动服务,发起请求

https://i-blog.csdnimg.cn/direct/dc023c5505ad456c97a0a7511d0a562e.png

时间大大缩小了