java中的本地緩存


java中的本地緩存,工作后陸續用到,一直想寫,一直無從下手,最近又涉及到這方面的問題了,梳理了一下。自己構造單例、guava、ehcache基本上涵蓋了目前的大多數行為了。
 
為什么要有本地緩存?
在系統中,有些數據,數據量小,但是訪問十分頻繁(例如國家標准行政區域數據),針對這種場景,需要將數據搞到應用的本地緩存中,以提升系統的訪問效率,減少無謂的數據庫訪問(數據庫訪問占用數據庫連接,同時網絡消耗比較大),但是有一點需要注意,就是緩存的占用空間以及緩存的失效策略。
 
為什么是本地緩存,而不是分布式的集群緩存?
         目前的數據,大多是業務無關的小數據緩存,沒有必要搞分布式的集群緩存,目前涉及到訂單和商品的數據,會直接走DB進行請求,再加上分布式緩存的構建,集群維護成本比較高,不太適合緊急的業務項目。
         這里介紹一下緩存使用的三個階段(摘自info架構師文檔)
          
 
本地緩存在那個區域?
         目前考慮的是占用了JVM的heap區域,再細化一點的就是heap中的old區,目前的數據量來看,都是一些小數據,加起來沒有幾百兆,放在heap區域最快最方便。后期如果需要放置在本地緩存的數據大的時候,可以考慮在off-heap區域(direct-memory 或者 big-memory),但是off-heap區域的話,需要考慮對象的序列化(因為off-heap區域存儲的是二進制的數據),另外一個的話就是off-heap的GC問題。其實,如果真的數據量比較大,那其實就可以考慮搞一個集中式的緩存系統,可以是單機,也可以是集群,來承擔緩存的作用。
 
搞一個單例模式,里面有個Map的變量來放置數據
關於單例模式,一個既簡單又復雜的模式(http://iamzhongyong.iteye.com/blog/1539642)
非常典型的代碼如下:
public class SingletonMap {
    //一個本地的緩存Map
    private Map localCacheStore = new HashMap(); 
 
    //一個私有的對象,非懶漢模式
    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);
    }
}
這種能不能用?可以用,但是非常局限
但是這種的就是本地緩存了嗎?答案顯然不是,為啥呢?
1、  沒有緩存大小的設置,無法限定緩存體的大小以及存儲數據的限制(max size limit);
2、  沒有緩存的失效策略(eviction policies);
3、  沒有弱鍵引用,在內存占用吃緊的情況下,JVM是無法回收的(weak rererences keys);
4、  沒有監控統計(statistics);
5、  持久性存儲(persistent store);
所以,這種就直接廢掉了。。。
 
引入EhCache來構建緩存(詳細介紹:  http://raychase.iteye.com/blog/1545906)
EhCahce的核心類:
A、CacheManager:Cache的管理類;
B、Cache:具體的cache類信息,負責緩存的get和put等操作
C、CacheConfiguration :cache的配置信息,包含策略、最大值等信息
D、Element:cache中單條緩存數據的單位
典型的代碼如下:
public static void main(String[] args) {
        //EhCache的緩存,是通過CacheManager來進行管理的
        CacheManager cacheManager = CacheManager.getInstance();
         
        //緩存的配置,也可以通過xml文件進行
        CacheConfiguration conf = new CacheConfiguration();
        conf.name("cache_name_default");//設置名字
        conf.maxEntriesLocalHeap(1000);//最大的緩存數量
        conf.memoryStoreEvictionPolicy(MemoryStoreEvictionPolicy.LRU);//設置失效策略
         
        //創建一個緩存對象,並把設置的信息傳入進去
        Cache localCache = new Cache(conf);
         
        //將緩存對象添加到管理器中
        cacheManager.addCache(localCache);
                 
        localCache.put(new Element("iamzhongyong", new Date()));
         
        System.out.println(localCache.getSize());
        System.out.println(localCache.getStatistics().toString());
        System.out.println(localCache.getName());
        System.out.println(localCache.get("iamzhongyong").toString());
        System.out.println(localCache.get("iamzhongyong").getObjectValue());   
    }
當然,Cache的配置信息,可以通過配置文件制定了。。。
優點:功能強大,有失效策略、最大數量設置等,緩存的持久化只有企業版才有,組件的緩存同步,可以通過jgroup來實現
缺點:功能強大的同時,也使其更加復雜
 
引入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 cache = CacheBuilder.newBuilder()       
            .maximumSize(20)//設置大小,條目數        
            .expireAfterWrite(20, TimeUnit.SECONDS)//設置失效時間,創建時間      
            .expireAfterAccess(20, TimeUnit.HOURS) //設置時效時間,最后一次被訪問       
            .removalListener(new RemovalListener() { //移除緩存的監聽器
                public void onRemoval(RemovalNotification notification) {
                    System.out.println("有緩存數據被移除了");
                }})
            .build(new CacheLoader(){ //通過回調加載緩存
                @Override
                public String load(String name) throws Exception {
                    return name + "-" + "iamzhongyong";
                }
        });
        System.out.println(cache.get(name));
        //cache.invalidateAll();
    }
}
 
緩存預熱怎么搞?
A、全量預熱,固定的時間段移除所有,然后再全量預熱
適用場景:
1、數據更新不頻繁,例如每天晚上3點更新即可的需求;
 2、數據基本沒有變化,例如全國區域性數據;
B、增量預熱(緩存查詢,沒有,則查詢數據庫,有則放入緩存)
適用場景:
1、  數據更新要求緩存中同步更新的場景
 
​集群內部,緩存的一致性如何保證?
如果采用ehcache的話,可以使用框架本身的JGroup來實現組內機器之間的緩存同步。
如果是采用google的cacheBuilder的話,需要自己實現緩存的同步。
A、非實時生效數據:數據的更新不會時時發生,應用啟動的時候更新即可,然后定時程序定時去清理緩存;
B、需要實時生效數據:啟動時可預熱也可不預熱,但是緩存數據變更后,集群之間需要同步

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM