【Memcached】初理解

Memcached最初是爲LiveJournal服務的,是爲了緩解數據庫壓力而構建的一個分佈式內存緩存系統。

在日常生活中,我們訪問的網站的所有數據基本上都是保存在數據庫中的,頻繁的獲取數據庫的數據會讓數據庫的性能降低,無法同時服務更多的用戶。 

大家都知道,當有一個request過來後,web服務器並從db中存取相關數據,但db存取的花費是相當高昂的。特別是每次都取相同的數據,等於是讓數據庫每次都在做高耗費的無用功,數據庫如果會說話,肯定會發牢騷,你都問了這麼多遍了,難道還記不住嗎?是啊,如果拿到第一次數據並存到內存裏,下次讀取時直接從內存裏讀取,而不用麻煩數據庫,這樣不就給數據庫減負了?而且從內存取數據必然要比從數據庫媒介取快很多倍,反而提升了應用程序的性能。

因此,我們可以在web與db層之間加一層cache層,主要目的:1.減少數據庫讀取負擔;2.提高數據讀取速度。而且,cache存取的媒介是內存,而一臺服務器的內存容量一般都是有限制的,不像硬盤容量可以做到TB級別。所以,可以考慮採用分佈式的cache層,這樣更易於破除內存容量的限制,同時又增加了靈活性。

特點

命令

Memcached的服務器客戶端通信並不使用複雜的XML等格式, 而使用簡單的基於文本行的協議。因此,通過telnet也能在Memcached上保存數據、取得數據。

set命令在memcached使用頻率極高。 

格式如下:set <key><flags><exptime><bytes>                  value                  

--<key>是客戶端所要求存儲的數據的鍵值                

--<flags>可以包括鍵值對的整型參數,客戶機使用它存儲關於鍵值對的額外信息                

--<exptime>在緩存中保存鍵值對的時間長度(以秒爲單位,0 表示永遠)                  

--<bytes>在緩存中存儲的字節數                

--<value>存儲的值(始終位於第二行)

set name 0 0 4
nasa
STORED //正確

get name
VALUE name  0 4
nasa
END


set name 0 0 5
nasa
CLIENT_ERROR bad data chunk //長度錯誤


add name 0 0 4
qwer
NOT_STORED //不可以
添加已存在的key

add gong 0 0 4
yuan
STORED //添加成功


replace name 0 0 4
NASA
STORED //已存在的key纔可以替換

replace x 0 0 4
NASA
NOT_STORED


delete name
DELETED //刪除成功

flush_all
OK //清空數據


內存存儲模式

如果需要申請內存時,memcached會劃分出一個新的page並分配給需要的slab區域。page一旦被分配在重啓前不會被回收或者重新分配,以解決內存碎片問題。 page:分配給Slab的內存空間,默認是1MB。分配給Slab之後根據slab的大小切分成chunk。 chunk:用於緩存記錄的內存空間。 slab申請內存時以page爲單位,所以在放入第一個數據,無論大小爲多少,都會有1M大小的page被分配給該slab。申請到 page後,slab會將這個page的內存按chunk的大小進行切分,這樣就變成了一個chunk的數組。

Slab Class 特定大小的chunk的組。 Memcached並不是將所有大小的數據都放在一起的,而是預先將數據空間劃分爲一系列slabs,每個slab只負責一定範圍內的數據存儲。memcached根據收到的數據的大小,選擇最適合數據大小的slab。memcached中保存着slab內空閒chunk的列表,根據該列表選擇chunk,然後將數據緩存於其中。 爲一個item分配存儲空間的時候,具體的操作是這樣的: 1、首先,計算該item佔用的空間大小,只有知道了它的大小,才能知道它需要存儲在哪個桶中。一個item的大小包括它的item結構體大小部分、名字長度部分、狀態標識部分、內容大小部分等的總和。 2、然後尋找合適的slab用於存儲,這一部分主要是比較item 和各slab桶的大小,尋找最合適的slab。

缺點

eg:將100字節的數據緩存到128字節的chunk中,剩餘的28字節就浪費了。

引入memcached時,最好重新計算一下數據的預期平均長度,調整growth factor,以獲得最佳的設置。 爲了避免使用Memcached時出現異常, 使用Memcached的項目需要注意: 1. 不能往Memcached存儲一個大於1MB的數據. 2. 往Memcached存儲的所有數據,如果數據的大小分佈於各種chunk大小區間,從64B到1MB都有,可能會造成內存的極大浪費以及Memcached的異常. Memcached最大可申請內存爲2M, 你第一次存儲一個10B的數據,那麼Memcached會申請1MB的內存,以64B進行分割然後存儲該數據, 第二次存儲一個90B的數據,那麼Memcached會繼續申請1M的內存,以128B進行分割然後存儲該數據, 第三次如果你想存儲一個150B的數據, 如果可以繼續申請內存, Memcached會申請1M內存以256B的大小進行分割, 但是由於最大可申請僅僅爲2MB,所以會導致該數據無法存儲.

緩存策略

1.LRU + 到期失效 :      

  • 優先使用已超時的記錄的空間        
  • 從最近未被使用的記錄中搜索,並將其空間分配給新的記錄

2.Lazy Expiration :    

  • 內部不會監視記錄是否過期,在get時查看記錄的時間戳,檢查記錄是否過期

工作原理

  • Memcached是以守護進程的方式運行在服務器端。    
  • 各個Memcached服務器之間互不通信,各自獨立存取數據,不共享任何信息。服務器並不具有分佈式功能,分佈式部署取決於memcache客戶端。

Memcached的分佈式

Memcached的分佈式Memcached的分佈式是由客戶端程序庫實現的。 存取對象的時候,每個對象都又一個唯一的標識符key,存取都通過這個key來進行,保存到memcached中的對象實際上都是放置在內存中的。

1.存儲數據的時候,key的值通過hash進行轉換,根據hash值來把value傳遞到對應的server上。

2.獲取對象數據時,根據key進行。首先對key進行hash,通過獲得的值可以確保它被存放在哪臺server上,然後在向該server發出請求。首先對key進行hash,通過獲得的值可以確定他被保存在了哪臺server上,然後再向該server發出請求。(client端只需要知道保存hash(key)的值在哪臺服務器上就可以了)

兩層哈希:

第一層在客戶端庫中實現;它將鍵散列到一個虛擬bucket列表中,每個bucket代表一個Memcached服務器,從而決定將請求發送給哪個Memcached服務器。

一旦完成,所選的Memcached服務器將使用一個典型的散列表。

餘數計算分散法

餘數計算分散簡單,數據發散較好 幾乎所有的緩存都會失效,緩存重組的代價非常大.(紅色部分代表miss)

一致性hash算法

將server的hash值分配至0~2^32的圓環上, 用同樣的方法求出存儲數值鍵的hash值並映射到圓上. 然後從數據映射到的位置開始順時針查找, 將數據存放至找到的第一臺服務器上. 如果超過0~2^32還找不到, 則將數據存放至第一臺服務器.
新添/刪除server時, 只在圓上增加服務器的逆時針方向的第一臺服務器上的鍵會受到影響。

優化一致性hash算法

  • 一般的一致性hash算法最大限度的抑制了鍵的重新分配
  • 服務器的映射地點的分佈非常的不均勻, 導致數據訪問傾斜, 大量的key被映射到同一臺服務器上
  1. 虛擬節點: 每臺機器計算出多個hash值, 每個值對應環上的一個節點位置          
  2. key的映射方式不變, 就多了層從虛擬節點到再映射到物理機的過程

優化後:在物理機很少的情況下, 只要虛擬節點足夠多, 也能使的key分佈相對均勻. 提升了算法的平衡性.

與Redis對比

不同點

Memcached

Redis

數據結構

支持簡單的K-V

支持string,hash,list,set, sorted set

線程

多線程

單線程

持久化

不可持久化

可持久化

分佈式

通過客戶端hash來實現分佈式

有主從結構

虛擬內存

LRU

將一些很久沒用的數據刷到磁盤

Memcached實驗性能

  1. 實驗一:3758條數據,單線程每次去Memcached隨機獲取一條數據(每條數據是1K)。
  2. 實驗二:10000000條數據,單線程每次去Memcached隨機獲取一條數據(每條數據是1K) 。

實驗一:

網絡

遠程/本地訪問Memcached

get時間/ms

1G

遠程

0.442

1G

本地

0.083

10G

遠程

0.139

10G

本地

0.084

 

實驗二:

網絡

遠程/本地訪問Memcached

get時間/ms

10G

遠程

0.036

10G

本地

0.024

假設 遠程訪問時間 = 計算時間+網絡通信時間,本地訪問 = 計算時間 (無網絡通信)      

那麼 : 遠程訪問時間-計算時間 = 網絡通信時間

網絡

實驗

網絡佔比網絡通信時間 遠程時間

1G

實驗一

0.81

10G

實驗一

 

0.40

1G

實驗二

 

-

10G

實驗二

 

0.32

在增加計算複雜度時,Memcached的網絡佔比還是較大,可以說明Memcached的查詢計算做的較好。

由於每次都是串行訪問數據,網絡帶寬綽綽有餘。所以網絡沒有發生一些競爭的現象,網絡帶來的佔比應該是網絡固有開銷造成的,猜測應該是找到了網絡的下界?

實驗二測試了Memcached 的add和get操作所花時間:

網絡

遠程/本地訪問Memcached

add時間/ms

get時間/ms

 

10G

遠程

0.053

0.036

 

10G

本地

0.020

0.024

當Memcached放在遠程(與客戶端不在一個機器)時,get比set時間快0.39倍=>Memcached是一個適合多讀少寫的系統。

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章