数据存储层
这里为什么说是存储层而不是持久层?因为 rigistry 本质上是一个双层的 ConcurrentHashMap,存储在内存中的。
- 第一层的 key 是spring.application.name,value 是第二层 ConcurrentHashMap;
- 第二层 ConcurrentHashMap 的 key 是服务的 InstanceId,value 是 Lease 对象
- Lease 对象包含了服务详情和服务治理相关的属性。
二级缓存层
Eureka 实现了二级缓存来保存即将要对外传输的服务信息,数据结构完全相同。
- 一级缓存:ConcurrentHashMap<Key,Value> readOnlyCacheMap,本质上是 HashMap,无过期时间,保存服务信息的对外输出数据结构。
- 二级缓存:Loading<Key,Value> readWriteCacheMap,本质上是 guava 的缓存,包含失效机制,保存服务信息的对外输出数据结构。
既然是缓存,那必然要有更新机制,来保证数据的一致性。下面是缓存的更新机制:
更新机制包含删除和加载两个部分,上图黑色箭头表示删除缓存的动作,绿色表示加载或触发加载的动作。
删除二级缓存:
- Eureka Client 发送 register、renew 和 cancel 请求并更新 registry 注册表之后,删除二级缓存;
- Eureka Server 自身的 Evict Task 剔除服务后,删除二级缓存;
- 二级缓存本身设置了 guava 的失效机制,隔一段时间后自己自动失效;
加载二级缓存:
- Eureka Client 发送 getRegistry 请求后,如果二级缓存中没有,就触发 guava 的 load,即从 registry 中获取原始服务信息后进行处理加工,再加载到二级缓存中。
- Eureka Server 更新一级缓存的时候,如果二级缓存没有数据,也会触发 guava 的 load。
更新一级缓存:
Eureka Server 内置了一个 TimerTask,定时将二级缓存中的数据同步到一级缓存(这个动作包括了删除和加载)。
服务注册机制
服务提供者、服务消费者、以及服务注册中心自己,启动后都会向注册中心注册服务(如果配置了注册)。下图是介绍如何完成服务注册的:
注册中心服务接收到 register 请求后:
- 保存服务信息,将服务信息保存到 registry 中;
- 更新队列,将此事件添加到更新队列中,供 Eureka Client 增量同步服务信息使用。
- 清空二级缓存,即 readWriteCacheMap,用于保证数据的一致性。
- 更新阈值,供剔除服务使用。
- 同步服务信息,将此事件同步至其他的 Eureka Server 节点。
服务续约机制
服务注册后,要定时(默认 30S,可自己配置)向注册中心发送续约请求,告诉注册中心“我还活着”。
注册中心收到续约请求后:
- 更新服务对象的最近续约时间,即 Lease 对象的 lastUpdateTimestamp;
- 同步服务信息,将此事件同步至其他的 Eureka Server 节点。
剔除服务之前会先判断服务是否已经过期,判断服务是否过期的条件之一是续约时间和当前时间的差值是不是大于阈值。