性能分析

 Memcached做爲一個內存key-value存儲容器有很是優秀的性能,可是在上次的使用中確發現大量的數據丟失狀況發生,致使cache的功能基本消失。具體的檢測方式以下:檢測命中率緩存

檢測命中率是一個最基本的、最宏觀的方式,使用telnet鏈接到memcached服務器,而後執行stats命令就能夠看到宏觀的一些信息,以下圖。
服務器

 

        這個命令中比較關鍵的屬性是get_hits和get_misses,get_hits表示讀取cache命中的次數,get_misses是讀取失敗的次數,即嘗試讀取不存在的緩存數據。
         命中率=get_hits / (get_hits + get_misses)
命中率越高說明cache起到的緩存做用越大。可是在實際使用中,這個命中率不是有效數據的命中率,有些時候get操做可能只是檢查一個key存在不存在,這個時候miss也是正確的,這就像用memcached做爲一種定時器,將一些臨時數據在memcache中存放特定時間長度,業務邏輯會根據cache是否存在而做不一樣的邏輯,這種數據其實已經不是單純的緩存了,也不該該統計到命中率中。再者,這個命中率是從memcached啓動開始全部的請求的綜合值,不能反映一個時間段內的狀況,因此要排查memcached的性能問題,還須要更詳細的數值。可是高的命中率仍是可以反映出memcached良好的使用狀況,忽然下跌的命中率可以反映大量cache丟失的發生。 memcached

Stats items性能

Stats items命令能夠查看每一個slab中存儲的item的一些詳細信息,具體能夠見下圖。
spa

 


關鍵屬性有: 對象

最後被剔除的數據在cache中存放的時間,以秒爲單位

stats items能夠詳細的觀察各slab的數據對象的狀況,由於memcached的內存分配策略致使一旦memcached的總內存達到了設置的最大內存,表明全部的slab可以使用的page都已經固定,這個時候若是還有數據放入,將開始致使memcached使用LRU策略剔除數據。而LRU策略不是針對全部的slabs,而是隻針對新數據應該被放入的slab,例若有一個新的數據要被放入slab 3,則LRU只對slab 3進行。經過stats items就能夠觀察到這些剔除的狀況。
具體分析以下: blog

evicted屬性
若是一個slab的evicted屬性不是0,則說明當前slab出現了提早剔除數據的狀況,這個slab多是你須要注意的。evicted_time屬性
若是evicted不爲0,則evicited_time就表明最後被剔除的數據時間緩存的時間。並非發生了LRU就代碼memcached負載過載了,由於有些時候在使用cache時會設置過時時間爲0,這樣緩存將被存放30天,若是內存慢了還持續放入數據,而這些爲過時的數據好久沒有被使用,則可能被剔除。須要注意的是,最後剔除的這個數據已經被緩存的時間,把evicted_time換算成標準時間看下是否已經達到了你能夠接受的時間,例如:你認爲數據被緩存了2天是你能夠接受的,而最後被剔除的數據已經存放了3天以上,則能夠認爲這個slab的壓力其實能夠接受的;可是若是最後被剔除的數據只被緩存了20秒,不用考慮,這個slab已經負載太重了。age屬性
age屬性反應了當前還在緩存的數據中最久的時間,它的大小和evicted_time沒有必然的大小關係,由於可能時間最久的數據確實頻繁被讀取的,這時候不會被LRU清理掉,可是若是它小於evicted_time的話,則說明數據在被下去讀取前就被清理了,或者存放了不少長時間可是不被使用的緩存對象。Stats slabs 內存

從Stats items中若是發現有異常的slab,則能夠經過stats slabs查看下該slab是否是內存分配的確有問題。
Stats slabs結果以下圖
ci

 

Stats slabs的屬性說明以下: get

 

   
chunk_size 當前slab每一個chunk的大小
chunk_per_page 每一個page可以存放的chunk數
total_pages 分配給當前slab的page總數
total_chunks 當前slab最多可以存放的chunk數,應該等於chunck_per_page * total_page
used_chunks 已經被佔用的chunks總數
free_chunks 過時數據空出的chunk裏尚未被使用的chunk數
free_chunks_end 新分配的可是尚未被使用的chunk數

 

這個命令的信息量很大,全部屬性都頗有價值。下面一一解釋各屬性:

綜合上面的數據,能夠發現形成memcached的內存使用率下降的屬性有:

chunk_size, chunk_per_page
這兩個屬性是固定的,可是它反映當前slab存儲的數據大小,能夠供你分析緩存數據的散列區間,經過調整增加因子能夠改變slab的區間分佈,從而改變數據散列到的區域。若是大量的230byte到260byte的數據,而恰好一個slab大小是250byte,則250byte到260byte的數據將被落到下一個slab,從而致使大量的空間浪費。total_pages
這個是當前slab總共分配大的page總數,若是沒有修改page的默認大小的狀況下,這個數值就是當前slab可以緩存的數據的總大小(單位爲M)。若是這個slab的剔除很是嚴重,必定要注意這個slab的page數是否是太少了。
我上次處理的那個項目由於和另外的一個項目共用的memcache,並且memcache已經運行了很長時間,致使page都已經所有被分配完,而恰好兩個項目的緩存數據大小差異不少,致使新項目數據最多的slab 4居然只有一個page,因此數據緩存不到22s就被替換了,徹底失去了緩存的意義。
針對我遇到的那個狀況,解決方案是從新分配page,或者重啓memcache服務。可是page reassign方法從1.2.8版已經徹底移除了,因此如今沒有辦法在線狀況下從新分配page了。另一種有些時候是不能夠接受的,由於一次緩存服務器的重啓將致使全部緩存的數據將從新從DB取出,這個可能形成db的壓力瞬間增大。並且有的緩存數據時不入庫的,這個時候咱們就須要作memcache的導入和導出了。在下篇文章中我會總結下memcache的dump操做。total_chunks
這個的做用和total_pages基本相同,不過這個屬性能夠更準確的反應實際能夠存放的緩存對象總數。used_chunks, free_chunks, free_chunks_end
這三個屬性相關度比較高,從數值上來看它們知足: 
                total_chunks = used_chunks + free_chunks + free_chunks_end
used_chunks就是字面的意思,已經使用的chunk數;free_chunks卻不是全部的未被使用的chunk數,而是曾經被使用過可是由於過時而被回收的chunk數;free_chunks_end是page中歷來沒有被使用過的chunk數。

 



      從上圖能夠看出,slab 1只放了一個對象,可是已經申請了一整個page,這個時候used_chunks爲1,可是free_chunks卻爲0,由於尚未任何回收的空間,而free_chunks_end卻等於10081,說明這麼多的chunk歷來沒有被使用過。下圖就是這個數據過時後的stats slabs數據,能夠發現free_chunks有值了,就是過時的那個chunk,因此是1,used_chunks爲0,free_chunks_end不變。

 



      爲何要分兩種free chunk呢?
      個人理解是這樣的:若是free_chunks_end不爲零,說明當前slab沒有出現過容量不夠的時候;而若是free_chunks始終爲0,說明不少數據過時時間過長或者在過時前就被剔除了,這個要結合剔除數據和數據保留的時間(age屬性)來看待。因此分開統計這兩個值能夠準確的判斷實際空閒的chunk的狀態,一旦因此的chunk被使用過一次之後,除非從新申請page,不然free_chunks_end始終爲0。因此對於運行時間比較久的memcached,可能大部分這個值都是0。active_slabs, total_malloced
在stats slabs輸出的最後兩項是兩個統計數據,一個是活動的slab總數,由於slab雖然帶編號,可是這個編號不必定是連續的,由於有可能有些中間區間的slab沒有值就沒有初始化,這樣之後該slab有值的時候就不用改變slab的編號了。因此活動的slab總數不必定等於slab的最大編號。
total_malloced這個是實際已經分配的總內存數,單位爲byte,這個數值決定了memcached實際還能申請多少內存,若是這個值已經達到設定的上限,則不會有新的page被分配,之前分配的page也已經固定slab了。

 

    綜合上面的數據,能夠發現形成memcached的內存使用率下降的屬性有:

 
page中歷來沒有被使用過的chunks;chunk中存放數據和chunk實際大小的差值;因爲短期的數據集中在某個slab區域,致使大量page被分配,而以後被閒置的內存,這些即便有整個page的空閒也不會被分配給實際壓力很大的slab區域(這個功能是否是之後memcached會考慮實現呢?)。 
相關文章
相關標籤/搜索