天天看點

Ehcache(03)——Ehcache中儲存緩存的方式 1       堆記憶體(MemoryStore) 2       非堆記憶體(BigMemory) 3       磁盤(DiskStore)

Ehcache中儲存緩存的方式

目錄

1     堆記憶體(MemoryStore)

1.1     指定可用記憶體

1.2     驅除政策

1.3     元素過期

2     非堆記憶體(BigMemory)

3     磁盤(DiskStore)

3.1     指定可用容量

3.2     元素過期

       在Ehcache中對于緩存的存儲主要有三種方式:分别是堆記憶體、非堆記憶體和磁盤。其中非堆記憶體是針對于企業版Ehcache才有的功能,它可以不受Java GC的影響,能夠建立很大的緩存。

       我們通常所有的MemoryStore實際上就是堆記憶體存儲。MemoryStore總是可用的,所有的元素都可以儲存在MemoryStore中。MemoryStore是線程安全的,相比另外兩種儲存方式而言其通路速度也是最快的。通常我們在往緩存裡面添加元素的時候,其首先就是存放在MemoryStore裡面的,但是我們又不能說連續不斷的往MemoryStore裡面存放元素,這就涉及到到底能放多少元素的問題。

       Ehcache規定我們在使用一個Cache時必須在CacheManager級别指定可用的記憶體大小或者是在Cache級别指定可用的記憶體大小或所允許存放的元素的最大數量。在CacheManager級别指定的記憶體大小是其内部所有Cache一起所能使用的記憶體的最大量。CacheManager級别指定記憶體大小是通過maxBytesLocalHeap來指定的,如:

       上面指定了我們的CacheManager所能使用的最大記憶體是500M。CacheManager級别指定了記憶體大小後我們在Cache上也可以指定其能使用的最大記憶體,但不能指定其所能存儲元素的最大數量。另外,如果我們的CacheManager沒有指定可用的記憶體大小,我們可以通過maxBytesLocalHeap在Cache級别指定可用的記憶體大小,或者通過maxEntriesLocalHeap在Cache級别指定允許儲存元素的最大數量,但是maxEntriesLocalHeap和maxBytesLocalHeap不能同時使用。如下在CacheManager級别使用maxBytesLocalHeap,然而在Cache級别使用maxEntriesLocalHeap是不行的。

       如下在Cache級别同時使用maxBytesLocalHeap和maxEntriesLocalHeap也是不行的。

       那麼當我們記憶體中的元素大小或者數量超過了預設的大小之後怎麼辦呢?這個時候如果我們設定了允許溢出,如overflowToDisk或overflowToOffHeap,則會把某些元素溢出到對應的儲存器中。如果不允許溢出,則會先删除原有的某些元素。至于是哪個元素溢出、哪個元素删除則在不存在逾時的情況下與我們的記憶體驅除政策有關,這是通過Cache的memoryStoreEvictionPolicy屬性來指定的。其可選值有LRU、LFU和FIFO,預設是LRU。但是如果有過期元素存在的話則會優先驅除已經過期的元素,然後再考慮驅除政策memoryStoreEvictionPolicy。

       LRU(Least Recently Used):最近最少使用。當我們把一個元素儲存到Cache中或者從Cache中取出時都會更新該元素的最後使用時間。當采用最近最少使用原則進行驅除時會優先把最後使用時間最早的元素進行驅除。

       LFU(Least Frequently Used):最不常使用的。每次我們從Cache中擷取一個元素時都會更新該元素的hitCount屬性值加1。當采用最不常使用原則進行驅除時hitCount屬性值最小的元素将優先驅除。

       FIFO(First In First Out):先進先出。當采用這種驅除原則時将優先驅除最先儲存的元素。

       在上文中我們已經知道在不存在元素過期的情況下,驅除哪個元素是與我們的記憶體驅除政策有關的。但如果存在過期元素的話則會優先驅除已經過期的元素。關于控制元素是否過期我們可以通過cache的幾個屬性來定義。

       timeToIdleSeconds:機關是秒,表示一個元素在不被請求的情況下允許在緩存中存在的最長時間。預設值是0,表示不限制。

       timeToLiveSeconds:機關是秒,表示一個元素不管有沒有被使用,其在緩存中允許存在的最長時間。預設是0,表示不限制。一般timeToLiveSeconds要比timeToIdleSeconds長,否則就timeToIdleSeconds就失去意義了。

       eternal:boolean類型,表示是否永恒,預設為false。當設為true時,表示緩存中的元素永遠不會過期,timeToIdleSeconds和timeToLiveSeconds就失去作用了。這個時候元素就隻能由驅除政策來進行驅除了。

       當我們的元素過期以後,為了保持Cache的性能,Ehcache不一定馬上就會将過期的元素删除或者驅除到其它存儲容器中,它可能還在原來的位置。之是以說不一定是因為有可能當一個元素過期時恰好Cache需要删除元素或者驅除元素到其它存儲容器中,這個時候我們的過期元素将優先被删除或者驅除。另外,當我們在請求一個元素的時候,如果Ehcache發現該元素已經過期的話也會立刻将該元素删除。

       在上面的配置中,我們指定了該Cache允許元素不被請求的時間是10分鐘,最大存活時間是1小時,使用的驅除政策是LFU(最不常使用)。

       非堆記憶體存儲是針對于企業版才有的功能,它可以不受Java GC的影響,能夠建立很大的緩存。BigMemory儲存的都是一個個的位元組,在儲存元素的時候Ehcache會對元素進行序列化再儲存到BigMemory中,然後在讀取的時候又會把讀取到的位元組進行反序列化。是以存放在其中的元素的key和value都必須是能夠序列化的。

       磁盤存儲可以存儲記憶體中驅除過來的元素,也可以在系統重新開機的時候将記憶體中的緩存資訊儲存起來,供系統重新啟動後使用。磁盤存儲是非必須的,但是使用DiskStore的時候我們需要指定一個磁盤目錄來存放緩存資訊。這可以在ehcache.xml檔案中的ehcahce元素下的定義一個diskStore元素并指定其path屬性。由diskStore元素是定義在ehcache元素下我們看出diskStore在CacheManager範圍内是共享的,其是線程安全的。如果我們沒有定義diskStore元素時,DiskStore會使用預設的目錄作為其存儲目錄,該目錄就是java.io.tmpdir,即Java的臨時目錄。當然我們也可以指定一個絕對路徑。當我們指定diskStore元素的path為以下值時會被替換為實際對應的目錄:

l  user.home:使用者的家目錄。

l  user.dir:使用者的目前工作目錄。

l  java.io.tmpdir:Java臨時目錄。

l  在指令行指定的屬性,如“java -Dehcache.disk.store.dir=D:\\abc …..”。

       子目錄的話可以這樣指定:user.home/ehcache。

       此外需要注意的是因為DiskStore是把資訊存放在磁盤上的,是以我們存放在磁盤上的元素必須是可以序列化的。CacheManager的DiskStore路徑一旦設定好了之後将不能再更改。如果硬是更改了,那麼我們的CacheManager需要基于新的路徑重建立立。

       指定可用容量的時候我們可以在CacheManager級别通過maxBytesLocalDisk來指定。而在Cache級别我們可以通過maxBytesLocalDisk和maxEntriesLocalDisk來指定。因為DiskStore是可選的,是以這些屬性也都是可選的。另外不像MemoryStore那樣,我們在Cache級别上可以同時指定maxBytesLocalDisk和maxEntriesLocalDisk。如:

       DiskStore中驅除元素跟MemoryStore中驅除元素的規則是不一樣的。當往DiskStore中添加元素且此時DiskStore中的容量已經超出限制時将采用LFU(最不常用)驅除規則将對應的元素進行删除,而且該驅除規則是不可配置的。

       DiskStore中的元素過期跟MemoryStore中的元素過期是同樣定義的。對于每一個Cache而言都擁有一個線程用于檢查并移除其中的過期元素。至于多久檢查一次,我們可以通過cache元素的diskExpiryThreadIntervalSeconds 屬性來指定,預設是每兩分鐘檢查一次。

(注:本文是基于Ehcache2.8.1所寫。)