Eureka 的工作原理和交互流程
Eureka 是 Netflix 开源的一款提供服务注册和发现的产品,它是 Spring Cloud 早期微服务架构中最核心的组件之一。
Eureka 的设计哲学是 “高可用性(AP)优先于强一致性(CP)”。以下是对 Eureka 工作原理和交互流程的深度解析。
一、 Eureka 的三大核心角色
在理解原理之前,需要先明确 Eureka 架构中的三个核心角色:
- Eureka Server(服务注册中心):负责管理、记录所有微服务节点的元数据(如 IP、端口、健康检查地址等),并提供服务发现功能。
- Service Provider(服务提供者):也是一个 Eureka Client。它在启动时将自身的网络信息注册到 Eureka Server,并定期发送心跳。
- Service Consumer(服务消费者):也是一个 Eureka Client。它从 Eureka Server 获取注册表信息,缓存在本地,并通过负载均衡(如 Ribbon)调用服务提供者。
(注:在实际业务中,一个微服务通常既是提供者又是消费者。)
二、 Eureka 的核心工作原理
Eureka 的高可用和稳定主要依赖于以下几个核心机制:
1. 去中心化集群(Peer-to-Peer 复制)
Eureka Server 集群采用 Peer-to-Peer(对等) 架构,没有 Master/Slave 的区分。
- 当一个 Eureka Server 接收到客户端的注册、下线或心跳请求时,它会将这个状态变更同步给集群中的其他 Server 节点。
- 即使集群中只剩下一个节点,Eureka 依然能提供完整的服务注册与发现功能(AP 特性)。
2. 客户端缓存机制
- Eureka Client 会周期性(默认 30 秒)从 Server 端拉取最新的服务注册表,并缓存在本地内存中。
- 业务调用时不经过 Eureka Server:消费者是直接根据本地缓存的服务列表,通过客户端负载均衡找到目标 IP 进行直连。
- 即使所有的 Eureka Server 都宕机了,消费者依然可以通过本地缓存正常调用现有的微服务,只是无法发现新的服务(高可用兜底)。
3. 自我保护机制(Self-Preservation)
这是 Eureka 最著名的特性之一,用于应对网络分区故障(Network Partition)。
- 触发条件:如果 Eureka Server 在短时间内丢失了过多客户端的心跳(默认是 15 分钟内低于预期心跳数的 85%)。
- 动作:Eureka Server 会认为“不是微服务挂了,而是我所在的网络出了问题”。此时,Server 会进入自我保护模式,停止剔除任何未按时发送心跳的微服务。
- 目的:宁可保留不健康的实例,也不盲目注销任何可能健康的实例。网络恢复后,它会自动退出该模式。
三、 Eureka 的核心交互流程(生命周期)
微服务在 Eureka 中的完整生命周期包含 6 个核心交互步骤(也是其内部的 REST API 动作):
1. Register(服务注册)
- 流程:Eureka Client 启动时,会将自己的元数据(应用名、IP、端口、状态等)封装成 HTTP POST 请求发送给 Eureka Server。
- Server 动作:Server 接收到请求后,将其存储在一个双层 Map 结构中(
ConcurrentHashMap<String, Map<String, Lease<InstanceInfo>>>,外层 Key 是应用名,内层 Key 是实例 ID),并同步给集群其他节点。
2. Renew(服务续约 / 心跳)
- 流程:注册成功后,Client 会开启一个定时任务,默认每隔 30 秒向 Server 发送一次 HTTP PUT 请求。
- 作用:告诉 Server “我还活着”。如果 Server 更新了该实例的最后更新时间,续约就成功了。
3. Fetch Registries(获取服务注册表)
- 流程:消费者 Client 启动时会进行一次全量拉取(Full Fetch)。之后会开启定时任务,默认每隔 30 秒进行一次增量拉取(Delta Fetch),获取自上次拉取之后发生变化的服务信息。
- 本地合并:Client 会将增量信息与本地缓存进行合并,并重新计算 Hash 值与 Server 端进行比对,若不一致则重新进行全量拉取。
4. Service Invocation(服务调用)
- 流程:消费者根据本地缓存的服务列表,配合负载均衡器(如 Ribbon 或 LoadBalancer),选择一台具体的 Provider 实例。
- 调用:直接发起 HTTP/RPC 调用。(此过程 Eureka Server 完全不参与)。
5. Cancel(服务下线)
- 流程:当微服务正常关闭时(如正常的停机部署),Client 会向 Server 发送一个 HTTP DELETE 请求。
- Server 动作:Server 收到请求后,会立即将该实例从注册表中删除,并将该下线事件同步给其他 Server 节点。
6. Eviction(服务剔除)
- 流程:当微服务异常宕机、断网或由于内存溢出直接死掉时,它无法发送 Cancel 请求。
- Server 动作:Eureka Server 内部有一个定时任务(EvictionTask,默认每 60 秒执行一次)。如果发现某个实例距离上次收到心跳的时间已经超过了规定的阈值(默认 90 秒),Server 就会将其从注册表中剔除(前提是未触发自我保护机制)。
四、 交互流程图解(文字版)
plaintext
[微服务提供者] [Eureka Server] [微服务消费者]
| | |
| 1. Register: 发送 IP/Port 等信息 | |
|------------------------------------->| |
| | |
| 2. Renew: 每 30s 发一次心跳续约 | |
|------------------------------------->| |
| | 3. Fetch: 每 30s 拉取一次最新注册表 |
| |<---------------------------------------|
| | (保存到本地缓存) |
| | |
| | 4. Call: 根据本地缓存列表,负载均衡调用|
|<==============================================================================|
| | |
| 5. Cancel: 正常停机发送下线请求 | |
|------------------------------------->| |
| | |
(宕机) | 6. Evict: 90s 未收到心跳,执行剔除任务 |
X |----(内部机制)----> X |
总结
Eureka 的核心逻辑非常清晰:它牺牲了数据的一致性(消费者拉取到的注册表可能有最多数十秒的延迟),换取了极高的系统可用性。在微服务架构中,偶尔调用到一个不可用的实例可以通过客户端重试机制来解决,但注册中心整体不可用是致命的,这就是 Eureka 采用 AP 架构的根本原因。