天天看點

Memcached深入剖析

Memcached基礎

What is Memcached ?

Free & open source, high-performance, distributed memory object caching system

一個開源,免費的高性能,分布式記憶體緩存系統。

在我們的應用程式中,一般會将資料庫的一些經常需要查詢用到的資料緩存至Memcached,以提高動态Web應用的響應速度。如下圖所示:

<a href="http://s3.51cto.com/wyfs02/M00/58/00/wKiom1SmQaGTfoRKAAE4oHmqY6s517.jpg" target="_blank"></a>

快速體驗Memcached

【關于libevent的簡要說明:libevent就是一個程式庫,他将Linux的epoll、BSD系統的kqueue等事件處理機制封裝成統一的接口,即使對伺服器的連接配接增加,也能發揮0(1)的性能。Memcached使用這個庫,可以在Linux平台上發揮其高性能。】

過程如下:

1

2

3

4

5

6

7

8

9

<code>tar</code> <code>-xf libevent-2.0.20-stable.</code><code>tar</code><code>.gz</code>

<code>cd</code> <code>libevent-2.0.20-stable</code>

<code>.</code><code>/configure</code> <code>--prefix=</code><code>/usr/local/libevent</code>

<code>make</code>

<code>make</code> <code>install</code>

<code>tar</code> <code>-xf memcached-1.4.22.</code><code>tar</code><code>.gz</code>

<code>cd</code> <code>memcached-1.4.22</code>

<code>.</code><code>/configure</code> <code>--prefix=</code><code>/usr/local/memached</code> <code>--with-libevent=</code><code>/usr/local/libevent/</code>

<code>make</code> <code>&amp;&amp; </code><code>make</code> <code>install</code>

啟動Memcached

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

<code>[root@www bin]</code><code># ./memcached -p 11211 -m 64 -f 1.5 -u nobody -vvv -d</code>

<code>slab class   1: chunk size        80 perslab   13107</code>

<code>slab class   2: chunk size       120 perslab    8738</code>

<code>slab class   3: chunk size       184 perslab    5698</code>

<code>slab class   4: chunk size       280 perslab    3744</code>

<code>slab class   5: chunk size       424 perslab    2473</code>

<code>slab class   6: chunk size       640 perslab    1638</code>

<code>slab class   7: chunk size       960 perslab    1092</code>

<code>slab class   8: chunk size      1440 perslab     728</code>

<code>slab class   9: chunk size      2160 perslab     485</code>

<code>slab class  10: chunk size      3240 perslab     323</code>

<code>slab class  11: chunk size      4864 perslab     215</code>

<code>slab class  12: chunk size      7296 perslab     143</code>

<code>slab class  13: chunk size     10944 perslab      95</code>

<code>slab class  14: chunk size     16416 perslab      63</code>

<code>slab class  15: chunk size     24624 perslab      42</code>

<code>slab class  16: chunk size     36936 perslab      28</code>

<code>slab class  17: chunk size     55408 perslab      18</code>

<code>slab class  18: chunk size     83112 perslab      12</code>

<code>slab class  19: chunk size    124672 perslab       8</code>

<code>slab class  20: chunk size    187008 perslab       5</code>

<code>slab class  21: chunk size    280512 perslab       3</code>

<code>slab class  22: chunk size    420768 perslab       2</code>

<code>slab class  23: chunk size    631152 perslab       1</code>

<code>slab class  24: chunk size   1048576 perslab       1</code>

可以利用./memcached -h的方式來了解一些選項的作用:

-p &lt;num&gt;      TCP port number to listen on (default: 11211)  指定端口

-l &lt;addr&gt;     interface to listen on (default: INADDR_ANY, all addresses)

監聽位址,想一想,如果我們的機器上有多個網卡我們監聽在哪個網卡上呢?

-d            run as a daemon  表示以一個背景服務的方式運作

-u &lt;username&gt; assume identity of &lt;username&gt; (only when run as root)  

以哪個使用者的身份運作

-m &lt;num&gt;      max memory to use for items in megabytes (default: 64 MB) 

以M為機關指定最大的記憶體空間

-f &lt;factor&gt;   chunk size growth factor (default: 1.25)  

指定增長因子

-n &lt;bytes&gt;    minimum space allocated for key+value+flags (default: 48)  

最小存儲機關。實際上,這裡指定的是最小的slab chunk大小

在上面啟動過程中,我們使用了-vvv的方式輸出了啟動過程的詳細資訊,那麼slab class , chunk這些是什麼呢?增長因子又是幹什麼的?

端口驗證:

<code>[root@www ~]</code><code># netstat -tnlp | grep 11211</code>

<code>tcp        0      0 0.0.0.0:11211         0.0.0.0:*    LISTEN      3292</code><code>/memcached</code>      

<code>tcp        0      0 :::11211              :::*         LISTEN      3292</code><code>/memcached</code>

Memcached啟動後,我們怎麼連接配接進行操作呢?

要知道Memcached是基于Client/Server架構的,上面的是啟動Server端,表示Memcached已經有64M記憶體空間來進行緩存資料管理。至于設定哪些緩存資料,資料有效期是多少等這些都是用戶端的事情。很多語言都實作了Memcached用戶端,比如Java/PHP等。需要注意的是,Memcached的一個重要特征--協定簡單。比如,我們就可以使用telnet來操作Memcached:

<code>[root@www ~]</code><code># telnet 192.168.204.88 11211</code>

<code>Trying 192.168.204.88...</code>

<code>Connected to www.zfz2.com (192.168.204.88).</code>

<code>Escape character is </code><code>'^]'</code><code>.</code>

<code>stats</code>

stats指令可以擷取到Memcached運作時相關資訊。

一些常用指令:

add指令  添加新鍵

add keyname flag timeout datasize

<code>add name 0 30 5</code>

<code>hello</code>

<code>STORED</code>

get指令  取得鍵值

get keyname

<code>get name</code>

<code>VALUE name 0 5</code>

<code>END</code>

set 無條件設定一個鍵

說白了,就是有鍵則覆寫,無鍵則添加。

set keyname flag timeout datasize

replace 替換已經存在的KEY

replace keyname flag timeout datasize

append keyname flag timeout append_datasize

prepend keyname flag timeout prepend_datasize

<code>add name 0 60 5</code>

<code>append name 0 60 2</code>

<code>aa</code>

<code>VALUE name 0 7</code>

<code>helloaa</code>

incr keyname increments  對鍵值增長

decr keyname decrements  對鍵值減少

<code>add score 0 120 1</code>

<code>1</code>

<code>incr score 2</code>

<code>3</code>

<code>get score</code>

<code>VALUE score 0 1</code>

delete keyname  删除指定鍵

flush_all       清理所有鍵

stats           狀态資訊

quit            表示退出

version         檢視版本

Memcached的記憶體存儲和删除機制

Memcached是一個緩存伺服器,并且它認為自己緩存的資料并不是關鍵性資料,也就是如果Memcached重新開機,緩存資料會丢失,需要重建立立。Memcached對高可用的支援不是很好,但是對分布式提供了很好的支援。下面我們來分析下Memcached的記憶體存儲機制:

Memcached的記憶體存儲機制采用了Slab Allocator的方式,按照預先規定的大小,将配置設定的記憶體分割成特定長度的塊,以減少記憶體碎片問題。Slab Allocator可以重複使用以配置設定的記憶體。如下圖所示:

<a href="http://s3.51cto.com/wyfs02/M00/58/00/wKioL1SnTinAkEbvAAFO-dwM2f8650.jpg" target="_blank"></a>

有多個Slab Class類别,每一個Slab Class裡面有多個相同大小的Chunk,而Chunk就是Memcached存儲資料的最小單元。當Memcached接受到資料需要緩存時,會選擇最适合資料大小的Slab,然後從Slab中選擇空閑的Chunk進行存儲。當然這種方式是無法避免記憶體浪費的。

在啟動Memcached時,我們指定了-f選項,其實是在指定Slab中Chunk大小的增長因子,這是Memcached為我們提供的一個可以進行調優的選項。我們可以根據用戶端緩存資料的大小,做一個預估,通過增長因子來調整Slab的差别,以獲得最恰當的設定。

在Memcached中緩存資料的時候,我們可以指定資料的失效期,可以指定到秒。那麼如果時間到了,Memcached會怎麼做呢?

Memcached并不會釋放已經配置設定的記憶體,逾時後,用戶端就無法在看到該記錄了。Memcached的删除機制思想如下:

LAZY機制

Memcached内部不會去監控記錄是否過期,而是在get的時候去判斷一下時間戳,這樣就知道是不是過期了。這樣的話,Memcached因為LAZY的機制不會在這個方面去占用CPU。

LRU算法

最近最少使用原理,當Memcached空間不足時,要清理,怎麼清理呢?就是清理那些最近未被使用的記錄的空間,将這些空間重新配置設定給新的記錄。

Memcached的分布式機制與一緻性雜湊演算法

當我們使用多台Memcached來緩存資料時,就利用到了Memcached的分布式。Memcached的分布式的最大特點是不互相通信。在分布式的情況下,當我們要儲存一個鍵時,可以簡單的根據鍵計算一個值,進而決定存儲至哪個Memcached中,當要get這個鍵的時候,利用同樣的方式到對應的Memcached伺服器中去取。比如,我們有10台Memcached(編号0-9),現在要儲存一個key,通過對key進行計算,比如取得它的HASH值,然後對10取餘,假設得到8,我們就将這個KEY存儲至編号為8的伺服器中。這樣的話,雖然算法上簡單,存取上實作了分布式,但是有一個明顯的缺點,就是如果增加或者減少了Memcached的節點個數,我們的大部分緩存就失效了,需要重建立立了。【原因在于取餘的結果發生了巨變】那麼有沒有一種方式,當我們增加或者減少Memcached節點個數時,帶來的影響最小呢?

關于一緻性HASH算法(Consistent Hashing)

<a href="http://s3.51cto.com/wyfs02/M01/58/03/wKiom1SnVK6A-pyRAAFR1OdEa2U133.jpg" target="_blank"></a>

基本原理說明:

有一個HASH環,分布着2的32次方個點,然後求出各個Memcached伺服器的HASH值,将其置于環上的各個點上。用相同的方式計算需要儲存的資料的鍵的HASH值,并映射到環上的位置,從映射處開始順時針開始查找最近的Memcached,找到後就儲存至這個伺服器。如果要取得資料,也采用相同的方式定位伺服器。

這種算法就是一緻性HASH算法,通過這樣可以在添加、删除伺服器時,最大限度的抑制鍵的重新分布。

本文轉自zfz_linux_boy 51CTO部落格,原文連結:http://blog.51cto.com/zhangfengzhe/1598626,如需轉載請自行聯系原作者