1. 程式人生 > >Memcached之你真正理解LRU嗎(4)

Memcached之你真正理解LRU嗎(4)

眾所周知,Memcached使用的是LRU(Least Recently Used最近最少使用)演算法來回收快取,將那些屬於LRU的資料移出記憶體,從而騰出空間來載入另外的資料。那麼Memcached的最近最少使用演算法是怎麼實現的呢?也許很多人都會回答:不就是在記憶體滿了的情況下,把最近最少使用的Key替換掉,然後插入新的Key-Value鍵值對嗎?其實不然,下面我們來深入的分析Memcached的LRU的內部實現,在分析LRU之前,讓我們先了解一下Memcached的內部原理。

Memcached的記憶體分配

Memcached是採用Slab Allocator機制分配、管理記憶體,首先,我們必須理解三個概念:

Slab    
相同Chunk大小的集合,一個Slab包含多個Page,一個Page(預設是1M)包含多個Chunk,Chunk就是最終存放資料的地方。
Page  
Page預設是1M,一個Page包含多個Chunk。
Chunk    
預設情況下Chunk的大小是:96,隨著指定的增長因子變化(引數 -f <factor>)

Slab Allocator機制是將分配給Memcached的記憶體,切分成若干個Slab,每個Slab下的Page的大小預設是1M,也就是說,如果一個Slab佔用了50M的記憶體的話,在預設的情況下就有50個Page。在Memcached啟動的時候是沒有活動的Slab的,在插入資料的時候,如果Chunk不夠用才會申請Slab,一旦分配了記憶體就不會釋放,重複利用。

具體如圖所示:


Memcached快取原理

Memcached根據收到的資料的大小,選擇最適合資料大小的Slab(如下圖)。 Memcached中儲存著slab內空閒chunk的列表,根據該列表選擇chunk,然後將資料緩存於其中。

Memcached的記憶體浪費:

將100位元組的資料快取到128位元組的chunk中,剩餘的28位元組就浪費了(如下圖):


瞭解了上面的一些Memcached基礎概念之後,我們接下來說一下Memcached LRU的原理。

Memcache LRU:

首先我們要知道:

1,Memcached的LRU演算法針對每個Slab執行,而不是針對整體。

2,資料只會存在指定的Slab中,即使該Slab已經滿了,而且更大的Slab有空間,這種情況會在指定的Slab執行LRU演算法,因為資料不會被存放到更大的Slab中。


一個Slab會有多個Page,一個page預設是1M,啟動Memcached會預分配1M,當1M的資料滿之後,如果有新資料進來,那麼會重新分配一個Page給這個slab,但是Memcached是有記憶體上限的,如果不能申請Page的話,這時候就要針對這個Slab再利用LRU演算法剔除掉最近最少使用的資料了。

注:

所有的Slab都會分配一個Page,就算超出了-m引數指定的記憶體大小。

過期的資料如果沒被顯式呼叫get,也要佔用空間。因為LRU是針對雙向連結串列前面的資料,每個Slab由兩個指標來維護該雙向連結串列,即heads和tails指標,分別指向最老的資料和最新的資料。這就可能導致沒有過期的資料被踢。

一種有效緩解使用LRU的方法是:

1,避免大物件

如果系統上只有及個別幾個大物件的話,會浪費記憶體空間,因為Slab申請了Page是不能釋放記憶體的,及個別大物件會導致Slab申請了記憶體資源而得不到充分的利用。

2,調整增長因子

根據專案的需求調整增長因子,使記憶體充分利用。

總而言之,言而總之,就是讓記憶體充分利用。避免Slab中的Chunk虛位以待。

參考文件:(以下的資料可以認真看一下,雖然有點老,對了解Memcached還是很有幫助的)