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、須要實時生效數據:啓動時可預熱也可不預熱,可是緩存數據變動後,集羣之間須要同步

相關文章
相關標籤/搜索