Eureka作为注册中心,其实就是各个微服务将自己的IP和端口号存放到注册中心里,形成一个注册表,当微服务调用的时候,调用方从注册中心的注册表中获取想要调用微服务的具体IP和端口号,请求服务。
Eureka的注册表获取机制有两种:①第一次拉取注册表时,全量拉取注册表信息,将所有微服务注册信息全部存储在注册表中;②每隔30s,增量拉取服务注册表。
多级缓存机制是Eureka client拉取注册表时使用的机制。在多级缓存机制中有两个缓存,1、只读缓存ReadOnlyCacheMap,2、读写缓存ReadWriteCacheMap
Eureka client拉取注册表时,会先从ReadOnlyCacheMap中获取注册表数据,如果获取不到再去ReadWriteCacheMap中找,如果找不到就重新从注册表中拉取。
ReadOnlyCacheMap就是一个普通的ConcurrentHashMap,ReadWriteCacheMap是guava cache,如果ReadWriteCacheMap读不到数据,就会通过ClassLoader的load方法直接从注册表获取数据再返回。
多级缓存机制有多种过期策略
- 主动过期:当服务实例发生注册、下线、故障的时候,ReadWriteCacheMap中所有的缓存过期掉
- 定时过期:readWriteCacheMap在构建的时候,指定了一个自动过期的时间,默认值就是180秒,所以你往readWriteCacheMap中放入一个数据,180秒过后,就将这个数据给他过期了
- 被动过期:默认是每隔30秒,执行一个定时调度的线程任务,对readOnlyCacheMap和readWriteCacheMap中的数据进行一个比对,如果两块数据是不一致的,那么就将readWriteCacheMap中的数据放到readOnlyCacheMap中来
通过过期的机制,可以发现一个问题,就是如果ReadWriteCacheMap发生了主动过期或定时过期,此时里面的缓存就被清空或部分被过期了,但是在此之前readOnlyCacheMap刚执行了被动过期,发现两个缓存是一致的,就会接着使用里面的缓存数据,所以可能会存在30秒的时间,readOnlyCacheMap和ReadWriteCacheMap的数据不一致
服务注册表的全量拉取很好理解,就是第一次的时候,从注册表全量拉取注册表到eureka client,后面的话就是增量拉取了
增量拉取注册表的实现借助了一个ConcurrentLinkedQueue类型的变量recentlyChangedQueue,通过名称我们就能知道这个变量的含义,最近改变的队列,默认情况下recentlyChangedQueue里面存放的是180秒内修改的服务实例信息,后台会有一个定时任务来维护recentlyChangedQueue,只有最近180秒内有变更的服务实例才会在里面
在增量拉取注册表时,会将本地的注册表和recentlyChangedQueue中的服务实例进行一个合并,将有变化的服务实例信息进行一个修改,保证本地的服务注册表信息和eureka server的服务注册表一致
在获取增量注册表信息的时候,同时获取了一个eureka server全量注册表的hash值,这个又是干什么用的呢?在eureka client增量同步注册表完成之后,也会计算一个hash值,然后将自己计算出来的这个hash值和eureka server全量注册表的hash值进行比对,如果是一致的,说明增量数据同步没问题,反之则说了增量数据同步出现了不一致,那么就会重新从eureka server全量拉取一份最新的服务注册表。