1. 程式人生 > >java本地快取技術或框架

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 MaplocalCacheStore = new HashMap();      //一個私有的物件,非懶漢模式     private staticSingletonMap singletonMap = newSingletonMap();     //私有構造方法,外部不可以new一個物件     privateSingletonMap(){     }      //靜態方法,外部獲得例項物件     public staticSingletonMap getInstance(){        return singletonMap;     }     //獲得快取中的資料     public ObjectgetValueByKey(String key){        return localCacheStore.get(key);     }     //向快取中新增資料     public voidputValue(String key , Object value){        localCacheStore.put(key, value);     } } 這種能不能用?可以用,但是非常侷限 但是這種的就是本地快取了嗎?答案顯然不是,為啥呢? 1、  沒有快取大小的設定,無法限定快取體的大小以及儲存資料的限制(max sizelimit); 2、  沒有快取的失效策略(eviction policies); 3、  沒有弱鍵引用,在記憶體佔用吃緊的情況下,JVM是無法回收的(weakrererences 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 = newCacheConfiguration();        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", newDate()));        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 voidmain(String[] args) throws Exception{        GuavaCacheBuilderTest cache = newGuavaCacheBuilderTest();        cache.getNameLoadingCache("bixiao");     }     public voidgetNameLoadingCache(String name) throws Exception{        LoadingCache cache = CacheBuilder.newBuilder()                .maximumSize(20)//設定大小,條目數                  .expireAfterWrite(20, TimeUnit.SECONDS)//設定失效時間,建立時間                .expireAfterAccess(20, TimeUnit.HOURS) //設定時效時間,最後一次被訪問                .removalListener(new RemovalListener() { //移除快取的監聽器               public voidonRemoval(RemovalNotification notification) {                  System.out.println("有快取資料被移除了");               }})            .build(newCacheLoader(){ //通過回撥載入快取               @Override               public String load(Stringname) 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、需要實時生效資料:啟動時可預熱也可不預熱,但是快取資料變更後,叢集之間需要同步