理解memcached的內存存儲--(操做系統內存分頁算法)

 

Slab Allocation機制:整理內存以便重複使用

最近的memcached默認狀況下采用了名爲Slab Allocator的機制分配、管理內存。 在該機制出現之前,內存的分配是經過對全部記錄簡單地進行malloc和free來進行的。 可是,這種方式會致使內存碎片,加劇操做系統內存管理器的負擔,最壞的狀況下, 會致使操做系統比memcached進程自己還慢。Slab Allocator就是爲解決該問題而誕生的。html

下面來看看Slab Allocator的原理。下面是memcached文檔中的slab allocator的目標:web

the primary goal of the slabs subsystem in memcached was to eliminate memory fragmentation issues totally by using fixed-size memory chunks coming from a few predetermined size classes.算法

也就是說,Slab Allocator的基本原理是按照預先規定的大小,將分配的內存分割成特定長度的塊, 以徹底解決內存碎片問題。緩存

Slab Allocation的原理至關簡單。 將分配的內存分割成各類尺寸的塊(chunk), 
並把尺寸相同的塊分紅組(chunk的集合)(圖1)。服務器

memcached-0002-01.png

圖1 Slab Allocation的構造圖memcached

並且,slab allocator還有重複使用已分配的內存的目的。 也就是說,分配到的內存不會釋放,而是重複利用。svn

Slab Allocation的主要術語

Pageui

分配給Slab的內存空間,默認是1MB。分配給Slab以後根據slab的大小切分紅chunk。this

Chunkspa

用於緩存記錄的內存空間。

Slab Class

特定大小的chunk的組。

在Slab中緩存記錄的原理

下面說明memcached如何針對客戶端發送的數據選擇slab並緩存到chunk中。

memcached根據收到的數據的大小,選擇最適合數據大小的slab(圖2)。 
memcached中保存着slab內空閒chunk的列表,根據該列表選擇chunk, 
而後將數據緩存於其中。

memcached-0002-02.png

圖2 選擇存儲記錄的組的方法

實際上,Slab Allocator也是有利也有弊。下面介紹一下它的缺點。

Slab Allocator的缺點

Slab Allocator解決了當初的內存碎片問題,但新的機制也給memcached帶來了新的問題。

這個問題就是,因爲分配的是特定長度的內存,所以沒法有效利用分配的內存。 例如,將100字節的數據緩存到128字節的chunk中,剩餘的28字節就浪費了(圖3)。

memcached-0002-03.png

圖3 chunk空間的使用

對於該問題目前尚未完美的解決方案,但在文檔中記載了比較有效的解決方案。

The most efficient way to reduce the waste is to use a list of size classes that closely matches (if that's at all possible) common sizes of objects that the clients of this particular installation of memcached are likely to store.

就是說,若是預先知道客戶端發送的數據的公用大小,或者僅緩存大小相同的數據的狀況下, 只要使用適合數據大小的組的列表,就能夠減小浪費。

可是很遺憾,如今還不能進行任何調優,只能期待之後的版本了。 可是,咱們能夠調節slab class的大小的差異。 接下來講明growth factor選項。

使用Growth Factor進行調優

memcached在啓動時指定 Growth Factor因子(經過-f選項), 
就能夠在某種程度上控制slab之間的差別。默認值爲1.25。 可是,在該選項出現以前,這個因子曾經固定爲2,稱爲「powers of 2」策略。

讓咱們用之前的設置,以verbose模式啓動memcached試試看:

$ memcached -f 2 -vv

下面是啓動後的verbose輸出:

slab class   1: chunk size    128 perslab  8192slab class   2: chunk size    256 perslab  4096slab class   3: chunk size    512 perslab  2048slab class   4: chunk size   1024 perslab  1024slab class   5: chunk size   2048 perslab   512slab class   6: chunk size   4096 perslab   256slab class   7: chunk size   8192 perslab   128slab class   8: chunk size  16384 perslab    64slab class   9: chunk size  32768 perslab    32slab class  10: chunk size  65536 perslab    16slab class  11: chunk size 131072 perslab     8slab class  12: chunk size 262144 perslab     4slab class  13: chunk size 524288 perslab     2

可見,從128字節的組開始,組的大小依次增大爲原來的2倍。 這樣設置的問題是,slab之間的差異比較大,有些狀況下就至關浪費內存。 所以,爲儘可能減小內存浪費,兩年前追加了growth factor這個選項。

來看看如今的默認設置(f=1.25)時的輸出(篇幅所限,這裏只寫到第10組):

slab class   1: chunk size     88 perslab 11915slab class   2: chunk size    112 perslab  9362slab class   3: chunk size    144 perslab  7281slab class   4: chunk size    184 perslab  5698slab class   5: chunk size    232 perslab  4519slab class   6: chunk size    296 perslab  3542slab class   7: chunk size    376 perslab  2788slab class   8: chunk size    472 perslab  2221slab class   9: chunk size    592 perslab  1771slab class  10: chunk size    744 perslab  1409

可見,組間差距比因子爲2時小得多,更適合緩存幾百字節的記錄。 從上面的輸出結果來看,可能會以爲有些計算偏差, 這些偏差是爲了保持字節數的對齊而故意設置的。

將memcached引入產品,或是直接使用默認值進行部署時, 最好是從新計算一下數據的預期平均長度,調整growth factor, 以得到最恰當的設置。內存是珍貴的資源,浪費就太惋惜了。

接下來介紹一下如何使用memcached的stats命令查看slabs的利用率等各類各樣的信息。

查看memcached的內部狀態

memcached有個名爲stats的命令,使用它能夠得到各類各樣的信息。 
執行命令的方法不少,用telnet最爲簡單:

$ telnet 主機名 端口號

鏈接到memcached以後,輸入stats再按回車,便可得到包括資源利用率在內的各類信息。 此外,輸入"stats slabs"或"stats items"還能夠得到關於緩存記錄的信息。 結束程序請輸入quit。

這些命令的詳細信息能夠參考memcached軟件包內的protocol.txt文檔。

$ telnet localhost 11211Trying ::1...
Connected to localhost.
Escape character is '^]'.
stats
STAT pid 481STAT uptime 16574STAT time 1213687612STAT version 1.2.5STAT pointer_size 32STAT rusage_user 0.102297STAT rusage_system 0.214317STAT curr_items 0STAT total_items 0STAT bytes 0STAT curr_connections 6STAT total_connections 8STAT connection_structures 7STAT cmd_get 0STAT cmd_set 0STAT get_hits 0STAT get_misses 0STAT evictions 0STAT bytes_read 20STAT bytes_written 465STAT limit_maxbytes 67108864STAT threads 4END
quit

另外,若是安裝了libmemcached這個面向C/C++語言的客戶端庫,就會安裝 memstat 這個命令。 使用方法很簡單,能夠用更少的步驟得到與telnet相同的信息,還能一次性從多臺服務器得到信息。

$ memstat --servers=server1,server2,server3,...

libmemcached能夠從下面的地址得到:

查看slabs的使用情況

使用memcached的創造着Brad寫的名爲memcached-tool的Perl腳本,能夠方便地得到slab的使用狀況 (它將memcached的返回值整理成容易閱讀的格式)。能夠從下面的地址得到腳本:

使用方法也極其簡單:

$ memcached-tool 主機名:端口 選項

查看slabs使用情況時無需指定選項,所以用下面的命令便可:

$ memcached-tool 主機名:端口

得到的信息以下所示:

 #  Item_Size   Max_age  1MB_pages Count   Full?
 1     104 B  1394292 s    1215 12249628    yes
 2     136 B  1456795 s      52  400919     yes
 3     176 B  1339587 s      33  196567     yes
 4     224 B  1360926 s     109  510221     yes
 5     280 B  1570071 s      49  183452     yes
 6     352 B  1592051 s      77  229197     yes
 7     440 B  1517732 s      66  157183     yes
 8     552 B  1460821 s      62  117697     yes
 9     696 B  1521917 s     143  215308     yes10     872 B  1695035 s     205  246162     yes11     1.1 kB 1681650 s     233  221968     yes12     1.3 kB 1603363 s     241  183621     yes13     1.7 kB 1634218 s      94   57197     yes14     2.1 kB 1695038 s      75   36488     yes15     2.6 kB 1747075 s      65   25203     yes16     3.3 kB 1760661 s      78   24167     yes

內存存儲的總結

本次簡單說明了memcached的緩存機制和調優方法。 但願讀者能理解memcached的內存管理原理及其優缺點。

下次將繼續說明LRU和Expire等原理,以及memcached的最新發展方向—— 可擴充體系(pluggable architecher))。






 題外話:其實memcached的內存分配是否是以爲和操做系統內存頁分配算法同樣。(當年考試就考那幾種頁替換算法)

相關文章
相關標籤/搜索