java应用中的本地缓存

java中的本地缓存,工做后陆续用到,一直想写,一直无从下手,最近又涉及到这方面的问题了,梳理了一下。本身构造单例、guava、ehcache基本上涵盖了目前的大多数行为了。
java

为何要有本地缓存?在 系统中,有些数据,数据量小,可是访问十分频繁(例如国家标准行政区域数据),针对这种场景,须要将数据搞到应用的本地缓存中,以提高系统的访问效率,减 少无谓的数据库访问(数据库访问占用数据库链接,同时网络消耗比较大),可是有一点须要注意,就是缓存的占用空间以及缓存的失效策略。数据库

所谓的本地混存是相对于网络而言的(包括集群,数据库访问等)缓存

为何是本地缓存,而不是分布式的集群缓存? 目前的数据,大可能是业务无关的小数据缓存,没有必要搞分布式的集群缓存,目前涉及到订单和商品的数据,会直接走DB进行请求,再加上分布式缓存的构建,集群维护成本比较高,不太适合紧急的业务项目。这里介绍一下缓存使用的三个阶段(摘自info架构师文档)网络

本地缓存在那个区域?  目前考虑的是占用了JVM的heap区域,再细化一点的就是heap中的old区,目前的数据量来看,都是一些小数据,加起来没有几百兆,放在heap区 域最快最方便。后期若是须要放置在本地缓存的数据大的时候,能够考虑在off-heap区域,可是off-heap区域的话,须要考虑对象的序列化(由于 off-heap区域存储的是二进制的数据),另一个的话就是off-heap的GC问题。其实,若是真的数据量比较大,那其实就能够考虑搞一个集中式 的缓存系统,能够是单机,也能够是集群,来承担缓存的做用。架构

搞一个单例模式,里面有个Map的变量来放置数据很是典型的代码以下:框架

public class SingletonMap {
    //一个本地的缓存Map
    private Map<String,Object> localCacheStore = new HashMap<String,Object>(); 
 
    //一个私有的对象,非懒汉模式
    private static SingletonMap singletonMap = new SingletonMap(); 
 
    //私有构造方法,外部不能够new一个对象
    private SingletonMap(){
    }  
 
    //静态方法,外部得到实例对象
    public static SingletonMap getInstance(){
        return singletonMap;
    }
 
    //得到缓存中的数据
    public Object getValueByKey(String key){
        return localCacheStore.get(key);
    }
    //向缓存中添加数据
    public void putValue(String key , Object value){
        localCacheStore.put(key, value);
    }
}

这种能不能用?能够用,可是很是局限:分布式

可是这种的就是本地缓存了吗?答案显然不是,为啥呢?
一、  没有缓存大小的设置,没法限定缓存体的大小以及存储数据的限制(max size limit);
二、  没有缓存的失效策略(eviction policies);
三、  没有弱键引用,在内存占用吃紧的状况下,JVM是没法回收的(weak rererences keys);
四、  没有监控统计(statistics);
五、  持久性存储(persistent store);
因此,这种就直接废掉了。。。

固然,Cache的配置信息,能够经过配置文件制定了。。。ide

优势:功能强大,有失效策略、最大数量设置等,缓存的持久化只有企业版才有,组件的缓存同步,能够经过jgroup来实现ui

缺点:功能强大的同时,也使其更加复杂google

引入guava的cacheBuilder来构建缓存

这个很是强大、简单,经过一个CacheBuilder类就能够知足需求。

缺点就是若是要组件同步的话,须要本身实现这个功能。

典型的代码以下:

public class GuavaCacheBuilderTest {    
    public static void main(String[] args) throws Exception{
        GuavaCacheBuilderTest cache = new GuavaCacheBuilderTest();
        cache.getNameLoadingCache("bixiao");
    }
    public void getNameLoadingCache(String name) throws Exception{
        LoadingCache<String, String> cache = CacheBuilder.newBuilder()       
            .maximumSize(20)//设置大小,条目数        
            .expireAfterWrite(20, TimeUnit.SECONDS)//设置失效时间,建立时间      
            .expireAfterAccess(20, TimeUnit.HOURS) //设置时效时间,最后一次被访问       
            .removalListener(new RemovalListener<String, String>() { //移除缓存的监听器
                public void onRemoval(RemovalNotification<String, String> notification) {
                    System.out.println("有缓存数据被移除了");
                }})
            .build(new CacheLoader<String, String>(){ //经过回调加载缓存
                @Override
                public String load(String name) throws Exception {
                    return name + "-" + "iamzhongyong";
                }
        });
        System.out.println(cache.get(name));
        //cache.invalidateAll();
    }
}

缓存预热怎么搞?

A、全量预热,固定的时间段移除全部,而后再全量预热

适用场景:

一、数据更新不频繁,例如天天晚上3点更新便可的需求;

 二、数据基本没有变化,例如全国区域性数据;

B、增量预热(缓存查询,没有,则查询数据库,有则放入缓存)

适用场景:

一、  数据更新要求缓存中同步更新的场景

 

集群内部,缓存的一致性如何保证?

若是采用ehcache的话,可使用框架自己的JGroup来实现组内机器之间的缓存同步。

若是是采用google的cacheBuilder的话,须要本身实现缓存的同步。

A、非实时生效数据:数据的更新不会时时发生,应用启动的时候更新便可,而后定时程序定时去清理缓存;

B、须要实时生效数据:启动时可预热也可不预热,可是缓存数据变动后,集群之间须要同步

相关文章
相关标签/搜索