抱歉,你查看的文章不存在

dubbo缓存代码分析

dubbo是Ali出品的soa框架,属于互联网企业常见的rpc选择框架。

前几篇分析了多级缓存的相关代码,本篇就dubbo的缓存进行梳理。

dubbo的缓存针对的是客户端的缓存,可以设计相关的缓存策略

结果缓存,用于加速热门数据的访问速度,Dubbo提供声明式缓存,以减少用户加缓存的工作量。

  • lru 基于最近最少使用原则删除多余缓存,保持最热的数据被缓存。
  • threadlocal 当前线程缓存,比如一个页面渲染,用到很多portal,每个portal都要去查用户信息,通过线程缓存,可以减少这种多余访问。
  • jcache 与JSR107集成,可以桥接各种缓存实现。

默认情况下使用的是lru策略。

dubbo中关于各种配置选择了扩展点作为配置选项 通常情况下使用SPI声明

/ 此方法已经getExtensionClasses方法同步过。
private Map<String, Class<?>> loadExtensionClasses() {
    final SPI defaultAnnotation = type.getAnnotation(SPI.class);
    if(defaultAnnotation != null) {
        String value = defaultAnnotation.value();
        if(value != null && (value = value.trim()).length() > 0) {
            String[] names = NAME_SEPARATOR.split(value);
            if(names.length > 1) {
                throw new IllegalStateException("more than 1 default extension name on extension " + type.getName()
                        + ": " + Arrays.toString(names));
            }
            if(names.length == 1) cachedDefaultName = names[0];
        }
    }
     
    Map<String, Class<?>> extensionClasses = new HashMap<String, Class<?>>();
    loadFile(extensionClasses, DUBBO_INTERNAL_DIRECTORY);
    loadFile(extensionClasses, DUBBO_DIRECTORY);
    loadFile(extensionClasses, SERVICES_DIRECTORY);
    return extensionClasses;
}
 
private static final String SERVICES_DIRECTORY = "META-INF/services/";
 
private static final String DUBBO_DIRECTORY = "META-INF/dubbo/";
 
private static final String DUBBO_INTERNAL_DIRECTORY = DUBBO_DIRECTORY + "internal/";

可以看到默认情况下 dubbo会加载三个文件夹目录,此时我们关注Cache。

可以看到/dubbo-2.5.3.jar!/META-INF/dubbo/internal/com.alibaba.dubbo.cache.CacheFactory

threadlocal=com.alibaba.dubbo.cache.support.threadlocal.ThreadLocalCacheFactory
lru=com.alibaba.dubbo.cache.support.lru.LruCacheFactory
jcache=com.alibaba.dubbo.cache.support.jcache.JCacheFactory

默认声明了3中缓存,和文档保持一致

@SPI("lru")
public interface CacheFactory {
 
    @Adaptive("cache")
    Cache getCache(URL url);
 
}

其次我们看到默认情况下如果Cache声明成true其实启用的是lru缓存也就是

com.alibaba.dubbo.cache.support.lru.LruCacheFactory

众所周知的是dubbo采用了filter作为拦截器来增强和扩展相关功能

我们看一下CacheFilter

/**
 * CacheFilter
 *
 * @author william.liangf
 */
@Activate(group = {Constants.CONSUMER, Constants.PROVIDER}, value = Constants.CACHE_KEY)
public class CacheFilter implements Filter {
 
    private CacheFactory cacheFactory;
 
    public void setCacheFactory(CacheFactory cacheFactory) {
        this.cacheFactory = cacheFactory;
    }
 
    public Result invoke(Invoker<?> invoker, Invocation invocation) throws RpcException {
        if (cacheFactory != null && ConfigUtils.isNotEmpty(invoker.getUrl().getMethodParameter(invocation.getMethodName(), Constants.CACHE_KEY))) {
            Cache cache = cacheFactory.getCache(invoker.getUrl().addParameter(Constants.METHOD_KEY, invocation.getMethodName()));
            if (cache != null) {
                String key = StringUtils.toArgumentString(invocation.getArguments());
                if (cache != null && key != null) {
                    Object value = cache.get(key);
                    if (value != null) {
                        return new RpcResult(value);
                    }
                    Result result = invoker.invoke(invocation);
                    if (! result.hasException()) {
                        cache.put(key, result.getValue());
                    }
                    return result;
                }
            }
        }
        return invoker.invoke(invocation);
    }
 
}
/**
 * AbstractCacheFactory
 *
 * @author william.liangf
 */
public abstract class AbstractCacheFactory implements CacheFactory {
     
    private final ConcurrentMap<String, Cache> caches = new ConcurrentHashMap<String, Cache>();
 
    public Cache getCache(URL url) {
        String key = url.toFullString();
        Cache cache = caches.get(key);
        if (cache == null) {
            caches.put(key, createCache(url));
            cache = caches.get(key);
        }
        return cache;
    }
 
    protected abstract Cache createCache(URL url);
 
}

可以看出缓存的key是以url作为key的,具体创建缓存的逻辑有各个实现类具体完成。

默认情况下采取lru缓存

/**
 * LruCache
 *
 * @author william.liangf
 */
public class LruCache implements Cache {
     
    private final Map<Object, Object> store;
 
    public LruCache(URL url) {
        final int max = url.getParameter("cache.size", 1000);
        this.store = new LinkedHashMap<Object, Object>() {
            private static final long serialVersionUID = -3834209229668463829L;
            @Override
            protected boolean removeEldestEntry(Entry<Object, Object> eldest) {
                return size() > max;
            }
        };
    }
 
    public void put(Object key, Object value) {
        synchronized (store) {
            store.put(key, value);
        }
    }
 
    public Object get(Object key) {
        synchronized (store) {
            return store.get(key);
        }
    }
 
}

默认情况下可以根据参数最多缓存1000个。当方法数较多(均开启了缓存&&参数各不相同)有可能出现内存撑爆(特别是结果集太大)使用时需要评估===》缓存是把双刃剑要考虑缓存的效率和减少对服务方的依赖但也要考虑缓存不一致的场景。特别要注意缓存要用在幂等性场合

上述代码中我们看到了一个经典的lru缓存实现,使用LinkedHashMap重载removeEldestEntry。

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

编辑于

后端之路

0 篇文章0 人订阅

相关文章

来自专栏SDNLAB

Open vSwitch系列之openflow版本兼容

众所周知Open vSwitch支持的openflow版本从1.0到1.5版本(当前Open vSwitch版本是2.3.2)通过阅读代码,处理openflow...

57313
来自专栏开发技术

Cassandra-java操作——基本操作

  接着上篇博客,我们来谈谈java操作cassandra; 上篇博客的环境:jdk1.7 + python2.7.10 + cassandra2.2.8; 由...

1182
来自专栏一个番茄说

让你在WebView中用JS调Native Object

之所做这个东西,源于之前项目中需要把一些页面用webView来呈现,但是web中需要调用native的方法,比如获取本地存的某些数据、调用摄像头等等,这里也就是...

1123
来自专栏IT杂记

通过Java程序提交通用Mapreduce任务并获取Job信息

背景 我们的一个业务须要有对MR任务的提交和状态跟踪的功能,须要通过Java代码提交一个通用的MR任务(包括mr的jar、配置文件、依赖的第三方jar包),并且...

1.1K5
来自专栏Golang语言社区

理解Go语言Web编程(上)

断断续续学Go语言很久了,一直没有涉及Web编程方面的东西。因为仅是凭兴趣去学习的,时间有限,每次去学,也只是弄个一知半解。不过这两天下定决心把Go语言Web编...

38412
来自专栏Java架构师学习

带你深入了解Java线程中的那些事

引言 说到Thread大家都很熟悉,我们平常写并发代码的时候都会接触到,那么我们来看看下面这段代码是如何初始化以及执行的呢? public class Thre...

3368
来自专栏坚毅的PHP

my php & mysql FAQ

php中文字符串长度及定长截取问题使用str_len("中国") 结果为6,php系统默认一个中文字符长度为3,可改用mb_strlen函数获得长度,mb_su...

3956
来自专栏犀利豆的技术空间

徒手撸框架--实现 RPC 远程调用

微服务已经是每个互联网开发者必须掌握的一项技术。而 RPC 框架,是构成微服务最重要的组成部分之一。趁最近有时间。又看了看 dubbo 的源码。dubbo 为了...

1532
来自专栏wannshan(javaer,RPC)

dubbo监控机制之监控数据上报分析

dubbo对服务运行的监控,是通过从provider和consumer方收集调用信息存盘后,再由监控中心对数据分析绘表的方式完成的。 具体实现是provide...

50611
来自专栏纯洁的微笑

Guava 源码分析(Cache 原理【二阶段】)

在上文「Guava 源码分析(Cache 原理)」中分析了 Guava Cache 的相关原理。

1811

扫码关注云+社区

领取腾讯云代金券