美文网首页
Dubbo配置参数详解-cache

Dubbo配置参数详解-cache

作者: codeimport | 来源:发表于2020-01-08 15:31 被阅读0次

Dubbo配置参数详解-cache

Dubbo是一个由阿里开源的服务治理框架,笔者的公司重度使用Dubbo。Dubbo开源这么多年,配置项已经非常丰富,了解各个配置项的作用也变得非常重要,本系列将从源代码的角度分析Dubbo目前的最新版本(2.7.4)各个常用的配置项的具体含义以及是怎么起作用的。

画外音:目前Dubbo在开源中国举办的2019年度最受欢迎中国开源软件中排名第3名,支持Dubbo的朋友可以去投票哇。2019年度最受欢迎中国开源软件

cache有啥用?

cache:默认不开启,如果设置了cache,consumer端调用服务时,不用每次都发送请求到provider,dubbo会把第一次请求获取的结果缓存起来,后面相同的调用都直接使用该缓存;

dubbo中cache可以设置为:"lru","threadlocal","jcache"

    /**
     * Specify cache implementation for service invocation, legal values include: lru, threadlocal, jcache
     */
    String cache() default "";

cache怎么使用?

在dubbo中使用cache很简单,直接设置cache就可以

    @Reference(cache = "lru")
    private HelloDubboService helloDubboService;

cache源码分析?

这里用常见的lru缓存分析下dubbo的缓存时如何实现的,是否有坑。
当Reference设置了cache后,consumer端的调用链会增加一个过滤器:CacheFilter

    /**
     * If cache is configured, dubbo will invoke method on each method call. If cache value is returned by cache store
     * then it will return otherwise call the remote method and return value. If remote method's return value has error
     * then it will not cache the value.
     * @param invoker    service
     * @param invocation invocation.
     * @return Cache returned value if found by the underlying cache store. If cache miss it will call target method.
     * @throws RpcException
     */
    @Override
    public Result invoke(Invoker<?> invoker, Invocation invocation) throws RpcException {
        if (cacheFactory != null && ConfigUtils.isNotEmpty(invoker.getUrl().getMethodParameter(invocation.getMethodName(), CACHE_KEY))) {
            //这个根据调用URL获取了Cache,这里的key可以认为是接口名+方法名
            Cache cache = cacheFactory.getCache(invoker.getUrl(), invocation);
            if (cache != null) {
                String key = StringUtils.toArgumentString(invocation.getArguments());
                //根据传入的参数获取结果
                Object value = cache.get(key);
                if (value != null) {
                    if (value instanceof ValueWrapper) {
                        return AsyncRpcResult.newDefaultAsyncResult(((ValueWrapper) value).get(), invocation);
                    } else {
                        return AsyncRpcResult.newDefaultAsyncResult(value, invocation);
                    }
                }
                Result result = invoker.invoke(invocation);
                if (!result.hasException()) {
                    cache.put(key, new ValueWrapper(result.getValue()));
                }
                return result;
            }
        }
        return invoker.invoke(invocation);
    }

首先根据URL获取了Cache,我们看下是怎么获取Cache的

    /**
     *  Takes URL and invocation instance and return cache instance for a given url.
     * @param url url of the method
     * @param invocation invocation context.
     * @return Instance of cache store used as storage for caching return values.
     */
    @Override
    public Cache getCache(URL url, Invocation invocation) {
        //将方法名拼接到URL中,所以key可以认为是接口名+方法名这种形式
        url = url.addParameter(METHOD_KEY, invocation.getMethodName());
        String key = url.toFullString();
        Cache cache = caches.get(key);
        if (cache == null) {
            caches.put(key, createCache(url));
            cache = caches.get(key);
        }
        return cache;
    }

可以看出dubbo是根据URL+调用方法名获取的Cache,如果没有对应的Cache,则新建一个。
那又是怎么根据方法参数获取返回值的呢?我们首先来看LruCache类

public class LruCache implements Cache {
    private final Map<Object, Object> store;

    public LruCache(URL url) {
        int max = url.getParameter("cache.size", 1000);
        this.store = new LRUCache(max);
    }

    public void put(Object key, Object value) {
        this.store.put(key, value);
    }

    public Object get(Object key) {
        return this.store.get(key);
    }
}

可以看到LruCache将缓存的工作委托给了store,store是一个LRUCache
画外音:一个叫LruCache,另一个叫LRUCache,是LruCache将工作委托给了LRUCache,这个命名是要吐槽一下,怎么不能学习下Mybatis的Cache命名;

我们在来看下LRUCache的具体实现:

public class LRUCache<K, V> extends LinkedHashMap<K, V> {

    private static final long serialVersionUID = -5167631809472116969L;

    private static final float DEFAULT_LOAD_FACTOR = 0.75f;

    private static final int DEFAULT_MAX_CAPACITY = 1000;
    private final Lock lock = new ReentrantLock();
    private volatile int maxCapacity;

    public LRUCache() {
        this(DEFAULT_MAX_CAPACITY);
    }

    public LRUCache(int maxCapacity) {
        super(16, DEFAULT_LOAD_FACTOR, true);
        this.maxCapacity = maxCapacity;
    }

    @Override
    protected boolean removeEldestEntry(java.util.Map.Entry<K, V> eldest) {
        return size() > maxCapacity;
    }
    
    //。。。。。。
}

可以看到,最终稿LRU缓存就是一个LinkedHashMap,默认大小是1000,也就是每一个接口只能缓存1000条数据,超过1000条数据就会将最近不常用的删掉;

cache有啥问题

经过分析Dubbo的缓存实现,发现有一个问题,缓存不能设置过期时间,也没找到清除缓存的接口,如果Provider的数据发生了变化,Consumer会一直拿不到最新的数据;

相关文章

网友评论

      本文标题:Dubbo配置参数详解-cache

      本文链接:https://www.haomeiwen.com/subject/msdsactx.html