PS:本篇源码涉及到的类,都是在原生的netflix-eureka模块中,基于v1.9.25 。
本来是想把服务端和客户端的注册表更新机制放在一篇文章里,写的时候发现服务端讲解已占篇幅比较大,故而拆开来讲。
Eureka
注册表简单介绍
eureka
中注册表是一个非常重要的概念,其实可以这么理解,不管是EurekaClient
端还是EurekaServer
端,都有一个map这样的数据结构,来存储应用的实例信息。比如,应用order-api
要通过eureka
方式访问user-api
时,是从order-api
本地的EurekaClient
注册表里根据user-api
(即clientName)来选择应用实例的地址,并请求数据,具体流程如图所示:
Eureka
注册表更新机制概览
还是画图根据客户端和服务端来简单介绍下注册表机制:
EurekaServer
注册表机制
获取注册表的入口
入口是在ApplicationResource
当中:
@GET
public Response getApplication(@PathParam("version") String version,
@HeaderParam("Accept") final String acceptHeader,
@HeaderParam(EurekaAccept.HTTP_X_EUREKA_ACCEPT) String eurekaAccept) {
......
String payLoad = responseCache.get(cacheKey);
...
if (payLoad != null) {
return Response.ok(payLoad).build();
} else {
return Response.status(Status.NOT_FOUND).build();
}
}
获取的方式,既支持application/xml
数据格式,也支持application/json
格式。
至于注册表,重点就是要关注ResponseCache
的实现类ResponseCacheImpl
。
ResponseCacheImpl
类解析
重要属性介绍
在此类中,我们能看到几个非常重要的属性:
//读缓存
private final ConcurrentMap<Key, Value> readOnlyCacheMap = new ConcurrentHashMap<Key, Value>();
//读写缓存
private final LoadingCache<Key, Value> readWriteCacheMap;
//是否应该使用读缓存,默认是true
private final boolean shouldUseReadOnlyResponseCache;
//实际操作读写缓存的类,含有读写锁
private final AbstractInstanceRegistry registry;
readOnlyCacheMap
不用多说,是一个线程安全的HashMap
,而readWriteCacheMap
是一个本地缓存类LoadingCache
,这里的一篇文章 java缓存架构剖析 讲得挺好的。
几种刷新注册表的方式
EurekaServer
端数据既然是存放在Map
数据结构里,那它是怎么去刷新里面的数据呢?我将定义成三种,主动刷新,被动刷新,定时刷新,下面一一介绍:
主动刷新
主动刷新,指的是应用实例(即EurekaClient
端)在进行注册,续约租期,更新状态,删除时,会主动来刷新readWriteCacheMap
中的数据,入口在AbstractInstanceRegistry
类,关键代码如下:
// AbstractInstanceRegistry类关键代码
// 这里只截取了注册相关代码,续约租期,更新状态,删除是类似的
public void register(InstanceInfo registrant