Netflix Eureka源码分析(13)——eureka server的注册表多级缓存过期机制:主动过期+定时过期+被动过期

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/A_Story_Donkey/article/details/82906908

(1)主动过期

readWriteCacheMap,读写缓存

有新的服务实例发生注册、下线、故障的时候,就会去刷新readWriteCacheMap

比如说现在有一个服务A,ServiceA,有一个新的服务实例,Instance010来注册了,注册完了之后,其实必须是得刷新这个缓存的,然后就会调用ResponseCache.invalidate(),将之前缓存好的ALL_APPS这个key对应的缓存,给它过期掉

将readWriteCacheMap中的ALL_APPS缓存key,对应的缓存给过期掉,比如新实例注册时的代码逻辑如下:

public abstract class AbstractInstanceRegistry implements InstanceRegistry {
 
    public void register(InstanceInfo registrant, int leaseDuration, boolean isReplication) {
            //注册的一些代码逻辑省略。。。
            //有新实例注册时将之前的ALL_APPS对应的注册表缓存过期掉
            invalidateCache(registrant.getAppName(), registrant.getVIPAddress(), registrant.getSecureVipAddress());
    }

    private void invalidateCache(String appName, @Nullable String vipAddress, @Nullable String secureVipAddress) {
        // invalidate cache
        responseCache.invalidate(appName, vipAddress, secureVipAddress);
    }
}
public class ResponseCacheImpl implements ResponseCache {
    
    //操作缓存过期的实现方法
    @Override
    public void invalidate(String appName, @Nullable String vipAddress, @Nullable String secureVipAddress) {
        for (Key.KeyType type : Key.KeyType.values()) {
            for (Version v : Version.values()) {
                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)定时过期

readWriteCacheMap在构建的时候,指定了一个自动过期的时间,默认值就是180秒,所以你往readWriteCacheMap中放入一个数据过后,自动会等180秒过后,就将这个数据给他过期了

public class ResponseCacheImpl implements ResponseCache {

    private final LoadingCache<Key, Value> readWriteCacheMap;
    
    ResponseCacheImpl(EurekaServerConfig serverConfig, ServerCodecs serverCodecs, AbstractInstanceRegistry registry) 
    {
        this.readWriteCacheMap =
                CacheBuilder.newBuilder().initialCapacity(1000)
                        .expireAfterWrite(serverConfig.getResponseCacheAutoExpirationInSeconds(), TimeUnit.SECONDS)
                        .removalListener(new RemovalListener<Key, Value>() {
                            @Override
                            public void onRemoval(RemovalNotification<Key, Value> notification) {
                                Key removedKey = notification.getKey();
                                if (removedKey.hasRegions()) {
                                    Key cloneWithNoRegions = removedKey.cloneWithoutRegions();
                                    regionSpecificKeys.remove(cloneWithNoRegions, removedKey);
                                }
                            }
                        })
                        .build(new CacheLoader<Key, Value>() {
                            @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;
                            }
                        });
    }

    }
@Singleton
public class DefaultEurekaServerConfig implements EurekaServerConfig {
    
    //返回缓存自动过期时间的配置项
    @Override
    public long getResponseCacheAutoExpirationInSeconds() {
        return configInstance.getIntProperty(
                namespace + "responseCacheAutoExpirationInSeconds", 180).get();
    }

}

(3)被动过期

readOnlyCacheMap怎么过期呢?

默认是每隔30秒,调用getCacheUpdateTask方法,执行一个定时调度的线程任务,TimerTask,有一个逻辑,会每隔30秒,对readOnlyCacheMap和readWriteCacheMap中的数据进行一个比对,如果两块数据是不一致的,那么就将readWriteCacheMap中的数据放到readOnlyCacheMap中来。

比如说readWriteCacheMap中,ALL_APPS这个key对应的缓存没了(缓存发生变动),那么最多30秒过后,就会同步到readOnelyCacheMap中去

public class ResponseCacheImpl implements ResponseCache {

    private final LoadingCache<Key, Value> readWriteCacheMap;
    
    ResponseCacheImpl(EurekaServerConfig serverConfig, ServerCodecs serverCodecs, AbstractInstanceRegistry registry) 
    {
        if (shouldUseReadOnlyResponseCache) {
            timer.schedule(getCacheUpdateTask(),
                    new Date(((System.currentTimeMillis() / responseCacheUpdateIntervalMs) * responseCacheUpdateIntervalMs)
                            + responseCacheUpdateIntervalMs),
                    responseCacheUpdateIntervalMs);
        }
    }

     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 {
                        CurrentRequestVersion.set(key.getVersion());
                        Value cacheValue = readWriteCacheMap.get(key);
                        Value currentCacheValue = readOnlyCacheMap.get(key);
                        //如果两块数据是不一致的,那么就将readWriteCacheMap中的数据放到readOnlyCacheMap中来。
                        if (cacheValue != currentCacheValue) {
                            readOnlyCacheMap.put(key, cacheValue);
                        }
                    } catch (Throwable th) {
                        logger.error("Error while updating the client cache from response cache", th);
                    }
                }
            }
        };
    }
}

 

(4)很重要的问题

假设有服务实例注册、下线、故障,要调用这个服务的其他服务,可能会过30秒之后才能感知到,为什么呢?因为这里在获取服务注册表的时候,有一个多级缓存的机制,最多是30秒才会去更新缓存

 

总结一张 eureka-server的多级缓存过期机制 流程图

猜你喜欢

转载自blog.csdn.net/A_Story_Donkey/article/details/82906908
今日推荐