Eureka
Eureka
一、原理分析
Eureka 是 Netflix 开源的服务发现组件,基于 REST 实现,主要用于 AWS 云环境中的中间层服务发现与故障转移。其核心原理围绕服务注册、心跳续约、服务剔除和客户端缓存等机制展开。
服务注册机制
服务实例启动时向 Eureka Server 发送 POST 请求注册自身信息,包含主机名、端口、健康检查 URL 等元数据。Eureka Server 将这些信息存储在双层结构的注册表中:
- 第一层存储服务实例的原始信息(读写频繁)
- 第二层存储经过压缩优化的只读数据(用于客户端查询)
注册表采用多级缓存设计,包括:
- 读写缓存(
ConcurrentHashMap
)- 只读缓存(定时从读写缓存同步)
- 客户端本地缓存(定时从服务器拉取)
心跳续约与健康检查
服务实例默认每 30 秒向 Eureka Server 发送心跳(PUT 请求续约)。若 90 秒内未收到续约,服务器将该实例标记为不可用。自我保护模式下,服务器会保留过期的实例注册信息。
健康检查机制分为两种:
- 客户端主动上报健康状态(集成 Spring Boot Actuator)
- 服务器端主动探测(需配置
eureka.server.healthcheck.enabled=true
)
服务剔除机制
Eureka Server 默认每 60 秒执行一次清理任务,移除超过 90 秒未续约的实例。自我保护模式触发条件为:
- 15 分钟内超过 85% 的实例未续约
- 满足条件时停止剔除实例,直到续约比例恢复正常
剔除算法采用加权随机选择,避免同时剔除大量实例导致服务雪崩。
客户端缓存与负载均衡
Eureka Client 每 30 秒从服务器拉取全量注册表,本地缓存采用双队列结构:
- 当前使用队列(
currentRegistry
) - 备用更新队列(
updateRegistry
)
Ribbon 集成时通过以下步骤实现动态负载均衡:
- 从 Eureka Client 获取服务实例列表
- 根据策略(轮询、随机等)选择实例
- 定期刷新服务器列表(默认 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 的管理页面即表示正常
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:10086
(10086
是 Eureka 服务本身的端口)。- UNKNOWN:有两个状态为
UP
的实例,地址分别为10.20.3.254:8081
和10.20.3.254:8080
。UNKNOWN
通常是因为服务实例未正确配置应用名称(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服务,模拟多实例部署,但为了避免端口冲突,需要修改端口设置:
若有其他需要区分的配置(如服务名、数据库连接等),也可通过 -D 参数指定:
-Dserver.port=8081 -Dspring.application.name=order-service-2
这样就启动了多个实例
四、服务发现
服务拉取是基于服务名称获取服务列表,然后对服务列表做负载均衡
1.修改服务的代码,修改访问的url路径,用服务名代替ip,端口:
2.在oder-service项目的启动类OrderApplication中的RestTemplate添加负载均衡注解:
五、Ribbon负载均衡
在远程调用时,我们使用@loadBalanced标记了RestTemplate,表示resrTemplate发起的请求要被Ribbon拦截和处理
@LoadBalanced
是 Spring Cloud 中的一个注解,主要用于实现客户端负载均衡。其核心原理基于 Ribbon 或 Spring Cloud LoadBalancer(新版本默认),通过动态选择服务实例来分发请求。核心工作机制
服务实例列表动态获取
通过服务注册中心(如 Eureka、Nacos)获取目标服务的所有可用实例列表,并定期更新。负载均衡策略
默认支持轮询(Round Robin)、随机(Random)、权重(Weighted)等算法,用户可自定义策略。例如:@Bean public IRule loadBalancerRule() { return new RandomRule(); // 随机策略 }
注解触发拦截器
在 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。
负载均衡策略
通过定义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
时,会从可用的服务实例中随机选择一个实例进行请求分发。
饥饿加载
来看看第一次请求的时间
ribbon默认是采用懒加载,即第一次访问时才创建LoadBalanceClient,请求时间会很长。而饥饿加载则会在项目创建时创建,降低第一次访问的耗时,通过下面配置开启饥饿加载:
# ribbon:
ribbon:
eager-load:
enabled: true #开启饥饿加载
clients: userserver #指定饥饿加载的服务名称
- userserver #如果有更多的服务需要饥饿加载,换行加杠,写上服务名称
重新启动服务,发起请求
时间大大缩小了