Netflix Eureka源码分析(12)——eureka server的注册表多级缓存机制源码剖析(只读缓存+读写缓存)

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

eureka client初始化的时候,就会自动发送个请求到eureka server拉一次性抓取全量的注册表,我们来看看eureka server端如何处理抓取全量注册表的请求的,eureka client发送的请求是:http://localhost:8080/v2/apps/,get请求

ApplicationsResource的getContainers()方法,获取全量注册表的方法

@Path("/{version}/apps")
@Produces({"application/xml", "application/json"})
public class ApplicationsResource {

    @GET
    public Response getContainers(@PathParam("version") String version,
                                  @HeaderParam(HEADER_ACCEPT) String acceptHeader,
                                  @HeaderParam(HEADER_ACCEPT_ENCODING) String acceptEncoding,
                                  @HeaderParam(EurekaAccept.HTTP_X_EUREKA_ACCEPT) String eurekaAccept,
                                  @Context UriInfo uriInfo,
                                  @Nullable @QueryParam("regions") String regionsStr) {

        boolean isRemoteRegionRequested = null != regionsStr && !regionsStr.isEmpty();
        String[] regions = null;
        if (!isRemoteRegionRequested) {
            EurekaMonitors.GET_ALL.increment();
        } else {
            regions = regionsStr.toLowerCase().split(",");
            Arrays.sort(regions); // So we don't have different caches for same regions queried in different order.
            EurekaMonitors.GET_ALL_WITH_REMOTE_REGIONS.increment();
        }

        // Check if the server allows the access to the registry. The server can
        // restrict access if it is not
        // ready to serve traffic depending on various reasons.
        if (!registry.shouldAllowAccess(isRemoteRegionRequested)) {
            return Response.status(Status.FORBIDDEN).build();
        }
        CurrentRequestVersion.set(Version.toEnum(version));
        KeyType keyType = Key.KeyType.JSON;
        String returnMediaType = MediaType.APPLICATION_JSON;
        if (acceptHeader == null || !acceptHeader.contains(HEADER_JSON_VALUE)) {
            keyType = Key.KeyType.XML;
            returnMediaType = MediaType.APPLICATION_XML;
        }

        Key cacheKey = new Key(Key.EntityType.Application,
                ResponseCacheImpl.ALL_APPS,
                keyType, CurrentRequestVersion.get(), EurekaAccept.fromString(eurekaAccept), regions
        );

        Response response;
        if (acceptEncoding != null && acceptEncoding.contains(HEADER_GZIP_VALUE)) {
            response = Response.ok(responseCache.getGZIP(cacheKey))
                    .header(HEADER_CONTENT_ENCODING, HEADER_GZIP_VALUE)
                    .header(HEADER_CONTENT_TYPE, returnMediaType)
                    .build();
        } else {
            response = Response.ok(responseCache.get(cacheKey))
                    .build();
        }
        return response;
    }

}

eureka server端,支持你来读取注册表的时候,搞了一套短小精干的多级缓存机制

也就是说,你eureka client发送请求过来读取全量注册表的时候,其实会从多级缓存里去读取注册表的数据,所以这里的cacheKey,就是全量注册表的缓存key

ResponseCache,就是eureka server端的缓存机制,通过 responseCache.getGZIP(cacheKey) 方法来获取缓存

    public byte[] getGZIP(Key key) {
        Value payload = getValue(key, shouldUseReadOnlyResponseCache);
        if (payload == null) {
            return null;
        }
        return payload.getGzipped();
    }

 

接着调用getValue(key, shouldUseReadOnlyResponseCache)方法实现多级缓存的逻辑

多级缓存机制,用了两个map,来做了两级缓存,只读缓存map,读写缓存map,先从只读缓存里去读,如果没有的话,会从读写缓存里去读。

    /**
     * Get the payload in both compressed and uncompressed form.
     */
    @VisibleForTesting
    Value getValue(final Key key, boolean useReadOnlyCache) {
        Value payload = null;
        try {
            if (useReadOnlyCache) {
                final Value currentPayload = readOnlyCacheMap.get(key);
                if (currentPayload != null) {
                    payload = currentPayload;
                } else {
                    payload = readWriteCacheMap.get(key);
                    readOnlyCacheMap.put(key, payload);
                }
            } else {
                payload = readWriteCacheMap.get(key);
            }
        } catch (Throwable t) {
            logger.error("Cannot get value for key :" + key, t);
        }
        return payload;
    }

 

如果读写缓存readWriteCacheMap还是没有呢?如果这个读写缓存,没有缓存的话,会从eureka server的注册表中去读取

从注册表中获取所有的Applications,ServerCodecs,json序列化的组件,将Applications对象序列化为了一个json字符串,将注册表中读取出来的Applications,放入读写缓存,接着放入只读缓存中去

最后呢,就是将从多级缓存机制中读取出来的全量的Applications作为响应来返回

最后总结一张 eureka-server的多级缓存机制 流程图:

猜你喜欢

转载自blog.csdn.net/A_Story_Donkey/article/details/82905448