栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

loud 之 eureka 源码解析(5)-Eureka注册表源码分析

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

loud 之 eureka 源码解析(5)-Eureka注册表源码分析

文章目录
  • Eureka注册表源码分析
    • 前言
      • 1、Eureka注册表整体流程图
    • 1、Eureka注册表二级缓存源码分析
      • 1.1 获取注册表流程源码入口
      • 1.2 getValue(获取缓存信息的方法)
      • 1.3 readonlyCacheMap (只读缓存,Map,没什么特殊的逻辑,简单)
      • 1.4 **readWriteCacheMap** (Guava 实现的 Cache 组件,需要看一下具体的逻辑)
      • 1.5 AbstractInstanceRegistry(注册表,其实也是一个 Map,没什么特别的逻辑,比如简单)
    • 2、Eureka注册表缓存过期机制源码分析
      • 2.1 缓存主动过期
      • 2.2 缓存被动过期(定时任务)
      • 2.3 缓存定时过期(缓存声明时设置)

Eureka注册表源码分析 前言 1、Eureka注册表整体流程图

1、Eureka注册表二级缓存源码分析 1.1 获取注册表流程源码入口
@GET
public Response getApplication(@PathParam("version") String version,
                               @HeaderParam("Accept") final String acceptHeader,
                               @HeaderParam(EurekaAccept.HTTP_X_EUREKA_ACCEPT) String eurekaAccept) {
    if (!registry.shouldAllowAccess(false)) {
        return Response.status(Status.FORBIDDEN).build();
    }

    EurekaMonitors.GET_APPLICATION.increment();

    CurrentRequestVersion.set(Version.toEnum(version));
    KeyType keyType = Key.KeyType.JSON;
    if (acceptHeader == null || !acceptHeader.contains("json")) {
        keyType = Key.KeyType.XML;
    }

    Key cacheKey = new Key(
            Key.EntityType.Application,
            appName,
            keyType,
            CurrentRequestVersion.get(),
            EurekaAccept.fromString(eurekaAccept)
    );
	
    
    // 这个就是获取的方法,主要看一下这里
    String payLoad = responseCache.get(cacheKey);

    if (payLoad != null) {
        logger.debug("Found: {}", appName);
        return Response.ok(payLoad).build();
    } else {
        logger.debug("Not Found: {}", appName);
        return Response.status(Status.NOT_FOUND).build();
    }
}
1.2 getValue(获取缓存信息的方法)
@VisibleForTesting
Value getValue(final Key key, boolean useReadOnlyCache) {
    Value payload = null;
    try {
        //1、判断是否开启使用只读缓存
        if (useReadOnlyCache) {
            // 1.1 为真从 readonlyCacehMap 中获取
            final Value currentPayload = readOnlyCacheMap.get(key);
            // 1.2 判断不为空,直接返回 
            if (currentPayload != null) {
                payload = currentPayload;
            } else {
                // 1.3 如果为空,则从 readWriteCacheMap 中获取,并写入到 readonlyCacheMap 中
                payload = readWriteCacheMap.get(key);
                readOnlyCacheMap.put(key, payload);
            }
        } else {
            //2、没有开户则直接从 readWriteCacheMap 中获取
            payload = readWriteCacheMap.get(key);
        }
    } catch (Throwable t) {
        logger.error("Cannot get value for key :" + key, t);
    }
    return payload;
}
1.3 readonlyCacheMap (只读缓存,Map,没什么特殊的逻辑,简单)

就是一个 ConcurrentHashMap,没有什么要说的。但是他有一个定时任务在实例化的时候就开启了

// ResponseCache 实例化的时候开启
// 开启更新 readonlyCacheMap 的定时任务
if (shouldUseReadOnlyResponseCache) {
    timer.schedule(getCacheUpdateTask(),
                   // 30s 之后触发
                   new Date(((System.currentTimeMillis() / responseCacheUpdateIntervalMs) * responseCacheUpdateIntervalMs)
                            + responseCacheUpdateIntervalMs),
                   // 每隔 30s 触发一次
                   responseCacheUpdateIntervalMs);
}
1.4 readWriteCacheMap (Guava 实现的 Cache 组件,需要看一下具体的逻辑)
//ResponseCache 实例化的时候构造的

this.readWriteCacheMap =
    // 1、 初始大小是 1000
    CacheBuilder.newBuilder().initialCapacity(1000)
    // 2、180s 过期
    .expireAfterWrite(serverConfig.getResponseCacheAutoExpirationInSeconds(), TimeUnit.SECONDS)
    // 3、注册了监听器
    .removalListener(new RemovalListener() {
        @Override
        public void onRemoval(RemovalNotification notification) {
            Key removedKey = notification.getKey();
            if (removedKey.hasRegions()) {
                Key cloneWithNoRegions = removedKey.cloneWithoutRegions();
                regionSpecificKeys.remove(cloneWithNoRegions, removedKey);
            }
        }
    })
    .build(new CacheLoader() {
        @Override
        public Value load(Key key) throws Exception {
            if (key.hasRegions()) {
                Key cloneWithNoRegions = key.cloneWithoutRegions();
                regionSpecificKeys.put(cloneWithNoRegions, key);
            }
            Value value = generatePayload(key);
            return value;
        }
    });
1.5 AbstractInstanceRegistry(注册表,其实也是一个 Map,没什么特别的逻辑,比如简单) 2、Eureka注册表缓存过期机制源码分析 2.1 缓存主动过期

在 com.netflix.eureka.registry.AbstractInstanceRegistry 中搜索 invalidateCache,可以发现有 4 个地方调用了失效缓存的方法

1>、cancel

2>、register

3>、statusUpdate

4>、deleteStatusOverride

所以这 4 种情况下都会去失效缓存,因为实例信息发生了变化,所以要把缓存失效掉

好,那我们来看一下失效缓存的方法

@Override
public void invalidate(String appName, @Nullable String vipAddress, @Nullable String secureVipAddress) {
    for (Key.KeyType type : Key.KeyType.values()) {
        for (Version v : Version.values()) {
            // 可以看到去失效 appName 对应的缓存,还有 ALL_APPS、ALL_APPS_DELTA 对应的缓存
            invalidate(
                    new Key(Key.EntityType.Application, appName, type, v, EurekaAccept.full),
                    new Key(Key.EntityType.Application, appName, type, v, EurekaAccept.compact),
                    new Key(Key.EntityType.Application, ALL_APPS, type, v, EurekaAccept.full),
                    new Key(Key.EntityType.Application, ALL_APPS, type, v, EurekaAccept.compact),
                    new Key(Key.EntityType.Application, ALL_APPS_DELTA, type, v, EurekaAccept.full),
                    new Key(Key.EntityType.Application, ALL_APPS_DELTA, type, v, EurekaAccept.compact)
            );
            if (null != vipAddress) {
                invalidate(new Key(Key.EntityType.VIP, vipAddress, type, v, EurekaAccept.full));
            }
            if (null != secureVipAddress) {
                invalidate(new Key(Key.EntityType.SVIP, secureVipAddress, type, v, EurekaAccept.full));
            }
        }
    }
}
2.2 缓存被动过期(定时任务)

readonlyCacheMap 有一个定时任务,会去不断的去与 readWriteCacheMap 对比,不同的话则需要去覆盖自身的值

private TimerTask getCacheUpdateTask() {
    return new TimerTask() {
        @Override
        public void run() {
            logger.debug("Updating the client cache from response cache");
            for (Key key : readOnlyCacheMap.keySet()) {
                if (logger.isDebugEnabled()) {
                    Object[] args = {key.getEntityType(), key.getName(), key.getVersion(), key.getType()};
                    logger.debug("Updating the client cache from response cache for key : {} {} {} {}", args);
                }
                try {
                    // 对比 readonlyCacheMap 中的信息和 readWriteCacheMap 中的信息,如果不一致,则更新 readonlyCacheMap 中的信息
                    CurrentRequestVersion.set(key.getVersion());
                    Value cachevalue = readWriteCacheMap.get(key);
                    Value currentCachevalue = readOnlyCacheMap.get(key);
                    if (cachevalue != currentCachevalue) {
                        readOnlyCacheMap.put(key, cachevalue);
                    }
                } catch (Throwable th) {
                    logger.error("Error while updating the client cache from response cache", th);
                }
            }
        }
    };
}
2.3 缓存定时过期(缓存声明时设置)

从 readWriteCacheMap 的声明中我们知道有一个过期的控制选项

.expireAfterWrite(serverConfig.getResponseCacheAutoExpirationInSeconds(), TimeUnit.SECONDS)

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/697269.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号