Memcache 學習總結

WHAT is Memcache?

Free & open source, high-performance, distributed memory object caching system, generic in nature, but intended for use in speeding up dynamic web applications by alleviating database load.
memcached是一個免費開源、高性能、分佈式的內存對象緩存系統,本質上是通用的,但旨在經過加速動態Web應用程序來減輕數據庫負載。php

圖片描述

Memcache是一款開發工具,其設計思想主要反映如下幾個方面:html

  1. 簡單的key/value存儲:服務器不關心數據自己意義及結構,主要是可序列化數據便可。
  2. 功能實現一半依賴與客戶端,一半基於服務器端。
  3. 各服務器間彼此無視,不在服務器間進行數據同步。
  4. O(1)的執行效率。
  5. 內存空間的再利用,Lazy Expiration + LRU 機制。

Memcache 與 memcached的區別

1.客戶端二者區別:web

  1. 兩個不一樣版本PHP的memcached的客戶端
  2. memcache是原生版本,徹底是在PHP框架內開發的,支持OO和非OO兩套接口並存;而memcached是創建在libmemcached的基礎上,只支持OO接口。
  3. 其餘一些實現和支持方面的不一樣等。

2.服務器端二者區別:算法

  1. Memcache 是項目名稱
  2. Memcached 是Memcache服務器端可執行文件的名稱,Memcached是以守護程序(監聽)方式運行於一個或多個服務器中,隨時會接收客戶端的鏈接和操做。

ps:本文說明的內容是關於memcache服務器的,請不要跟客戶端的叫法混淆。數據庫

Memcached內置內存存儲方式

1. Memcached 的高性能緩存

首先從內存模型來研究memcached:C++裏分配內存有兩種方式,預先分配和動態分配內存,顯然預先分配內存會使程序比較快,可是它的缺點是不能有效利用內存;而動態分配能夠有效利用內存,可是會使程序運行效率降低,memcached的內存分配就是基於以上原理,顯然爲了得到更快的速度,有時候咱們不得不以空間換時間。
Memcached的高性能源於兩階段哈希(two-stage-hash)結構。Memcached就像一個巨大的、存儲了不少<key, value>對的哈希表,經過key能夠存儲或查詢任意的數據。客戶端能夠把數據存儲在多臺memcached上,當查詢數據時,客戶端首先參考節點列表計算出key的哈希值(階段一哈希),進而選中一個節點;客戶端將請求發送給選中的節點,而後memcached節點經過一個內部的哈希算法(階段二哈希),查找真正的數據(item)並返回個客戶端。從實現的角度看,memcached是一個非阻塞、基於事件驅動的服務器程序。
爲了提升性能,memcacahed中保存的數據都存儲在memcached內置的內存存儲空間中。因爲數據僅存在於內存中,所以重啓memcached、重啓操做系統會致使所有數據丟失。另外,內存容量達到指定值以後,就基於LRU(Least Recently Used)算法自動刪除不使用的緩存。memcached自己是爲了緩存而設計的服務器,所以並無過多考慮數據的永久性問題。服務器

圖片描述

2. Slab Allocator 內存分配、管理機制app

1.在該機制出現之前,內存的分配是經過對全部記錄簡單地進行malloc和free 來進行的。可是,這種方式會致使內存碎片,加劇操做系統內存管理器的負擔,最壞的狀況下,會致使操做系統比memcached 進程自己還慢。Slab Allocator 就是爲解決該問題而誕生的, 它按照預先規定的大小,將分配的內存分割成特定長度的塊,以完成解決內存碎片的問題。存儲結構圖以下:框架

圖片描述

Memcached的存儲涉及到slab、page、chunk三個概念
chunk:固定大小的內存空間,用於緩存記錄,默認爲88Byte。
page:分配給Slab的內存空間,默認是1M。分配給Slab以後根據Slab的大小切成chunk。
slab:一樣大小的chunk組成一類slab。分佈式

2.在Slab中緩存記錄的原理
memcached 根據收到的數據大小,選擇最適合數據大小的Slab,memcached中保存着Slab內空閒chunk的列表,根據該列表選擇chunk,而後將數據緩存其中。Slab allocator分配的內存不會釋放,而是重複利用。

圖片描述

3.Slab Allocator 的缺點
因爲分配的是特定長度的內存,所以沒法有效的利用分配的內存。對與該問題沒有完美的解決方案,但能夠調節slab class的大小差異來減小空間浪費。

圖片描述

4.使用Growth Factor進行調優
memcached在啓動時制定Growth Factor因子(經過f選項),就能夠在某種程度上控制slab之間的差別。默認值時1.25.

Memcached 刪除機制

memcached是緩存,不須要永久的保存到服務器上,下面介紹它的刪除機制:
1.Lazy Expiration
memcached 不會釋放已經分配的內存,記錄過時後,客戶端沒法在看到這條記錄,其存儲空間能夠再利用。memcached內部不會監視記錄是否過時,而是在get時查看記錄的時間戳,檢查記錄是否過時。這種技術被稱爲Lazy Expiration。所以,memcached不會在過時監視上耗費CPU時間。

2.LRU(Least Recently Used)
memcached會優先使用已超時的記錄空間,但即便如此,也會發生追加新記錄時空間不足的狀況,此時就要使用名爲LRU機制來分配空間。顧名思義,這是刪除「最近最少使用」記錄的機制。所以,當memcahced的內存空間不足時(沒法從slab class獲取新的空間時),就從最近未被使用的記錄中搜索,並將其空間分配給新的記錄。

Memcached 分佈式算法

1.Memcached "分佈式"

特別澄清一個問題:MemCache雖然被稱爲"分佈式緩存",可是MemCache自己徹底不具有分佈式的功能,Memcache集羣之間不會相互通訊(與之造成對比的,好比JBoss Cache,某臺服務器有緩存數據更新時,會通知集羣中其餘機器更新緩存或清除緩存數據),所謂的"分佈式",徹底依賴於客戶端程序的實現。前面已經講過memcached的兩段哈希了,數據的保存和獲取都使用相同的算法。這樣將不一樣的鍵保存到不一樣的服務器上,就實現了memcached的分佈式。Memcached服務器增多後,鍵就會分散,即便一臺memcached服務器發生故障沒法鏈接,也不會影響其餘的緩存,系統依然能繼續進行。

2.餘數分佈式算法

就是「根據服務器臺數的餘數進行分散」。求得鍵的整數哈希值,再除以服務器臺數,根據其他數來選擇服務器。
餘數算法的缺點:餘數計算的方法簡單,數據的分散性也至關優秀,但也有其缺點。那就是當添加或移除服務器時,緩存重組的代價至關巨大。添加服務器後,餘數就會產生鉅變,這樣就沒法獲取與保存時相同的服務器,從而影響緩存的命中率。

3.Consistent hashing(一致哈希)

首先求出memcached 服務器(節點)的哈希值,並將其配置到0~2^32-1 的圓(continuum)上。而後用一樣的方法求出存儲數據的鍵的哈希值,並映射到圓上。而後從數據映射到的位置開始順時針查找,將數據保存到找到的第一個服務器上。若是超過2^32-1仍然找不到服務器,就會保存到第一臺memcached 服務器上。

圖片描述

從上圖的狀態中添加一臺Memcached 服務器。餘數分佈式算法因爲保存鍵的服務器會發生巨大變化,而影響緩存的命中率,但Consistent Hashing中,只有在continuum 上增長服務器的地點逆時針方向的第一臺服務器上的鍵會受到影響。

圖片描述

Consistent Hashing(添加服務器):
所以,Consistent Hashing 最大限度地抑制了鍵的從新分佈。並且,有的Consistent Hashing 的實現方法還採用了虛擬節點的思想。使用通常的hash函數的話,服務器的映射地點的分佈很是不均勻。所以,使用虛擬節點的思想,爲每一個物理節點(服務器)在continum上分配100~200 個點。這樣就能抑制分佈不均勻,最大限度地減少服務器增減時的緩存從新分佈。
經過上文中介紹的使用Consistent Hashing 算法的Memcached 客戶端函數庫進行測試的結果是,由服務器臺數(n)和增長的服務器臺數(m)計算增長服務器後的命中率計算公式: (1 -m/(n+m)) * 100

經常使用命令介紹

1.存儲及刪除命令,簡單易用,使用語法以下:
command <key> <flags> <expiration time> <bytes>
<value>
參數說明以下:
command set/add/replace
key key 用於查找緩存值
flags 能夠包括鍵值對的整型參數,客戶機使用它存儲關於鍵值對的額外信息
expiration time 在緩存中保存鍵值對的時間長度(以秒爲單位,0 表示永遠)
bytes 在緩存中存儲的字節數
value 存儲的值(始終位於第二行)

  1. set 命令用於向緩存添加新的鍵值對,若是已經存在,則以前的值將被替換。設置成功,服務器會使用單詞STORED進行響應。
  2. add 僅當緩存中不存在鍵時,add 命令纔會向緩存中添加一個鍵值對。若是緩存中已經存在鍵,則以前的值將仍然保持相同,而且您將得到響應 NOT_STORED。
  3. replace 僅當鍵已經存在時,replace 命令纔會替換緩存中的鍵。若是緩存中不存在鍵,那麼您將從 memcached 服務器接受到一條 NOT_STORED 響應。
  4. delete 刪除命令的語法:command <key>,delete 命令用於刪除 memcached 中的任何現有值。您將使用一個鍵調用delete,若是該鍵存在於緩存中,則刪除該值。若是不存在,則返回一條NOT_FOUND 消息。

2.讀取命令

  1. get 命令用於檢索與以前添加的鍵值對相關的值。當使用一個鍵來調用 get,若是這個鍵存在於緩存中,則返回相應的值。若是不存在,則不返回任何內容。get命令的key能夠表示一個或者多個鍵,鍵之間以空格隔開。
  2. gets 命令比普通的get命令多返回一個數字。這個數字能夠檢查數據是否發生變化:當key對應的數據變化時,這個數字也會改變。
  3. cas 即check and set,只有當最後一個參數和gets所獲取的參數匹配時才能存儲,不然返回「EXISTS」。

圖片描述

3.統計命令

  1. stats 顯示服務器信息、統計數據
  2. stats settings 顯示全部的參數設置
  3. stats slabs 顯示各個slab的信息,包括chunk的大小、數目、使用狀況等
  4. stats items 顯示各個slab的item信息
  5. stats cachedump slab_id limit_num 查看指定slab前limit_num個item,[key,expiration_time]
  6. flush_all 用於清理緩存中全部鍵值對
  7. stats reset 清空統計數據

運行狀態分析

1.stats指令解讀

stats是一個比較重要的指令,用於列出當前MemCache服務器的狀態,返回的參數反映着Memcache服務器的基本信息,他們的意思是:

參  數  名 做      用
pid MemCache服務器的進程id 
uptime 服務器已經運行的秒數
time 服務器當前的UNIX時間戳 
version MemCache版本 
pointer_size 當前操做系統指針大小,反映了操做系統的位數,64意味着MemCache服務器是64位的 
rusage_user 進程的累計用戶時間 
rusage_system  進程的累計系統時間 
curr_connections   當前打開着的鏈接數
total_connections    當服務器啓動之後曾經打開過的鏈接數
connection_structures  服務器分配的鏈接構造數 
cmd_get  get命令總請求次數 
cmd_set set命令總請求次數 
cmd_flush flush_all命令總請求次數 
get_hits 總命中次數,重要,緩存最重要的參數就是緩存命中率,以get_hits / (get_hits + get_misses)表示,好比這個緩存命中率就是99.2% 
get_misses  總未命中次數 
auth_cmds  認證命令的處理次數 
auth_errors  認證失敗的處理次數 
bytes_read  總讀取的字節數
bytes_written  總髮送的字節數 
 limit_maxbytes 分配給MemCache的內存大小(單位爲字節) 
accepting_conns  是否已經達到鏈接的最大值,1表示達到,0表示未達到
listen_disabled_num  統計當前服務器鏈接數曾經達到最大鏈接的次數,這個次數應該爲0或者接近於0,若是這個數字不斷增加, 就要當心咱們的服務了
threads  當前MemCache總線程數,因爲MemCache的線程是基於事件驅動機制的,所以不會一個線程對應一個用戶請求 
bytes  當前服務器存儲的items總字節數
current_items  當前服務器存儲的items總數量 
total_items  自服務器啓動之後存儲的items總數量 

比較關注的點:get_hits 和 get_misses,命中率:get_hits/(get_hits + get_misses) 是衡量memcache服務器的一個重要指標。

2.stats slabs 指令解讀

參  數  名 做      用
chunk_size 當前slab每一個chunk的大小,單位爲字節
chunks_per_page 每一個page能夠存放的chunk數目,因爲每一個page固定爲1M即10241024字節,因此這個值就是(10241024/chunk_size)
total_pages 分配給當前slab的page總數
total_chunks 當前slab最多可以存放的chunk數,這個值是total_pages*chunks_per_page
used_chunks 已經被分配給存儲對象的chunks數目
free_chunks 曾經被使用過可是由於過時而被回收的chunk數
free_chunks_end 新分配但尚未被使用的chunk數,這個值不爲0則說明當前slab歷來沒有出現過容量不夠的時候
mem_requested 當前slab中被請求用來存儲數據的內存空間字節總數,(total_chunks*chunk_size)-mem_requested表示有多少內存在當前slab中是被閒置的,這包括未用的slab+使用的slab中浪費的內存
get_hits 當前slab中命中的get請求數
cmd_set 當前slab中接收的全部set命令請求數
delete_hits 當前slab中命中的delete請求數
incr_hits 當前slab中命中的incr請求數
decr_hits 當前slab中命中的decr請求數
cas_hits 當前slab中命中的cas請求數
cas_badval 當前slab中命中可是更新失敗的cas請求數

經過此命令返回的信息,能夠查看slab class的分佈狀況,以及每一個slab中chunk使用狀況;根據slab的分佈,能夠判斷增加因子的設置的是否合理等。

3.stats items 命令解讀

參數名 做用
outofmemory slab class爲新item分配空間失敗的次數。這意味着你運行時帶上了-M或者移除操做失敗
number 存放的數據總數
age 存放的數據中存放時間最久的數據已經存在的時間,以秒爲單位
evicted 不得不從LRU中移除未過時item的次數 
evicted_time 自最後一次清除過時item起所經歷的秒數,即最後被移除緩存的時間,0表示當前就有被移除,用這個來判斷數據被移除的最近時間
evicted_nonzero 沒有設置過時時間(默認30天),但不得不從LRU中清除該未過時的item的次數

由於memcached的內存分配策略致使一旦memcached的總內存達到了設置的最大內存,表示全部的slab可以使用的page都已經固定,這時若是還有數據放入,將致使memcached使用LRU策略剔除數據。而LRU策略不是針對全部的slabs,而是隻針對新數據應該被放入的slab,例若有一個新的數據要被放入slab 3,則LRU只對slab 3進行,經過stats items就能夠觀察到這些剔除的狀況。
注意evicted_time:並非發生了LRU就表明memcached負載過載了,由於有些時候在使用cache時會設置過時時間爲0,這樣緩存將被存放30天,若是內存滿了還持續放入數據,而這些爲過時的數據好久沒有被使用,則可能被剔除。把evicted_time換算成標準時間看下是否已經達到了你能夠接受的時間,例如:你認爲數據被緩存了2天是你能夠接受的,而最後被剔除的數據已經存放了3天以上,則能夠認爲這個slab的壓力其實能夠接受的;可是若是最後被剔除的數據只被緩存了20秒,不用考慮,這個slab已經負載太重了。

注意問題

  1. memcache已經分配的內存不會再主動清理。
  2. memcache分配給某個slab的內存頁不能再分配給其餘slab。
  3. flush_all不能重置memcache分配內存頁的格局,只是給全部的item置爲過時。
  4. memcache最大存儲的item(key+value)大小限制爲1M,這由page大小1M限制
  5. 因爲memcache的分佈式是客戶端程序經過hash算法獲得的key取模來實現,不一樣的語言可能會採用不一樣的hash算法,一樣的客戶端程序也有可能使用相異的方法,所以在多語言、多模塊共用同一組memcached服務時,必定要注意在客戶端選擇相同的hash算法
  6. 啓動memcached時能夠經過-M參數禁止LRU替換,在內存用盡時add和set會返回失敗
  7. memcached啓動時指定的是數據存儲量,沒有包括自己佔用的內存、以及爲了保存數據而設置的管理空間。所以它佔用的內存量會多於啓動時指定的內存分配量,這點須要注意。
  8. memcache存儲的時候對key的長度有限制,php和C的最大長度都是250

參考文檔

https://www.cnblogs.com/xrq73...
http://zhihuzeye.com/archives...

相關文章
相關標籤/搜索