摘要:余數分布式算法就是根據服務器臺數的余數進行分散。余數分布式算法由于保存鍵的服務器會發生巨大變化,而影響緩存的命中率,但中,只有在上增加服務器的地點逆時針方向的第一臺服務器上的鍵會受到影響。
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應用程序來減輕數據庫負載。
Memcache是一款開發工具,其設計思想主要反映以下幾個方面:
簡單的key/value存儲:服務器不關心數據本身意義及結構,主要是可序列化數據即可。
功能實現一半依賴與客戶端,一半基于服務器端。
各服務器間彼此無視,不在服務器間進行數據同步。
O(1)的執行效率。
內存空間的再利用,Lazy Expiration + LRU 機制。
Memcache 與 memcached的區別1.客戶端兩者區別:
兩個不同版本PHP的memcached的客戶端
memcache是原生版本,完全是在PHP框架內開發的,支持OO和非OO兩套接口并存;而memcached是建立在libmemcached的基礎上,只支持OO接口。
其他一些實現和支持方面的不同等。
2.服務器端兩者區別:
Memcache 是項目名稱
Memcached 是Memcache服務器端可執行文件的名稱,Memcached是以守護程序(監聽)方式運行于一個或多個服務器中,隨時會接收客戶端的連接和操作。
ps:本文說明的內容是關于memcache服務器的,請不要跟客戶端的叫法混淆。
Memcached內置內存存儲方式1. Memcached 的高性能
首先從內存模型來研究memcached:C++里分配內存有兩種方式,預先分配和動態分配內存,顯然預先分配內存會使程序比較快,但是它的缺點是不能有效利用內存;而動態分配可以有效利用內存,但是會使程序運行效率下降,memcached的內存分配就是基于以上原理,顯然為了獲得更快的速度,有時候我們不得不以空間換時間。
Memcached的高性能源于兩階段哈希(two-stage-hash)結構。Memcached就像一個巨大的、存儲了很多
為了提高性能,memcacahed中保存的數據都存儲在memcached內置的內存存儲空間中。由于數據僅存在于內存中,因此重啟memcached、重啟操作系統會導致全部數據丟失。另外,內存容量達到指定值之后,就基于LRU(Least Recently Used)算法自動刪除不使用的緩存。memcached本身是為了緩存而設計的服務器,因此并沒有過多考慮數據的永久性問題。
2. Slab Allocator 內存分配、管理機制
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是緩存,不需要永久的保存到服務器上,下面介紹它的刪除機制:
1.Lazy Expiration
memcached 不會釋放已經分配的內存,記錄過期后,客戶端無法在看到這條記錄,其存儲空間可以再利用。memcached內部不會監視記錄是否過期,而是在get時查看記錄的時間戳,檢查記錄是否過期。這種技術被稱為Lazy Expiration。因此,memcached不會在過期監視上耗費CPU時間。
2.LRU(Least Recently Used)
memcached會優先使用已超時的記錄空間,但即使如此,也會發生追加新記錄時空間不足的情況,此時就要使用名為LRU機制來分配空間。顧名思義,這是刪除“最近最少使用”記錄的機制。因此,當memcahced的內存空間不足時(無法從slab class獲取新的空間時),就從最近未被使用的記錄中搜索,并將其空間分配給新的記錄。
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
參數說明如下:
command set/add/replace
key key 用于查找緩存值
flags 可以包括鍵值對的整型參數,客戶機使用它存儲關于鍵值對的額外信息
expiration time 在緩存中保存鍵值對的時間長度(以秒為單位,0 表示永遠)
bytes 在緩存中存儲的字節數
value 存儲的值(始終位于第二行)
set 命令用于向緩存添加新的鍵值對,如果已經存在,則之前的值將被替換。設置成功,服務器會使用單詞STORED進行響應。
add 僅當緩存中不存在鍵時,add 命令才會向緩存中添加一個鍵值對。如果緩存中已經存在鍵,則之前的值將仍然保持相同,并且您將獲得響應 NOT_STORED。
replace 僅當鍵已經存在時,replace 命令才會替換緩存中的鍵。如果緩存中不存在鍵,那么您將從 memcached 服務器接受到一條 NOT_STORED 響應。
delete 刪除命令的語法:command
2.讀取命令
get 命令用于檢索與之前添加的鍵值對相關的值。當使用一個鍵來調用 get,如果這個鍵存在于緩存中,則返回相應的值。如果不存在,則不返回任何內容。get命令的key可以表示一個或者多個鍵,鍵之間以空格隔開。
gets 命令比普通的get命令多返回一個數字。這個數字可以檢查數據是否發生變化:當key對應的數據變化時,這個數字也會改變。
cas 即check and set,只有當最后一個參數和gets所獲取的參數匹配時才能存儲,否則返回“EXISTS”。
3.統計命令
stats 顯示服務器信息、統計數據
stats settings 顯示所有的參數設置
stats slabs 顯示各個slab的信息,包括chunk的大小、數目、使用情況等
stats items 顯示各個slab的item信息
stats cachedump slab_id limit_num 查看指定slab前limit_num個item,[key,expiration_time]
flush_all 用于清理緩存中所有鍵值對
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已經負載過重了。
memcache已經分配的內存不會再主動清理。
memcache分配給某個slab的內存頁不能再分配給其他slab。
flush_all不能重置memcache分配內存頁的格局,只是給所有的item置為過期。
memcache最大存儲的item(key+value)大小限制為1M,這由page大小1M限制
由于memcache的分布式是客戶端程序通過hash算法得到的key取模來實現,不同的語言可能會采用不同的hash算法,同樣的客戶端程序也有可能使用相異的方法,因此在多語言、多模塊共用同一組memcached服務時,一定要注意在客戶端選擇相同的hash算法
啟動memcached時可以通過-M參數禁止LRU替換,在內存用盡時add和set會返回失敗
memcached啟動時指定的是數據存儲量,沒有包括本身占用的內存、以及為了保存數據而設置的管理空間。因此它占用的內存量會多于啟動時指定的內存分配量,這點需要注意。
memcache存儲的時候對key的長度有限制,php和C的最大長度都是250
參考文檔https://www.cnblogs.com/xrq73...
http://zhihuzeye.com/archives...
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/61738.html
摘要:豐富的特性具有豐富的特性,比如可以用作分布式鎖可以持久化數據可以用作消息隊列排行榜計數器還支持通知過期等等。比如利用布隆過濾器,內部維護一系列合法有效的,迅速判斷出請求所攜帶的是否合法有效。 showImg(https://segmentfault.com/img/remote/1460000019070847?w=750&h=300); 場景:Redis面試 showImg(http...
摘要:豐富的特性具有豐富的特性,比如可以用作分布式鎖可以持久化數據可以用作消息隊列排行榜計數器還支持通知過期等等。比如利用布隆過濾器,內部維護一系列合法有效的,迅速判斷出請求所攜帶的是否合法有效。 showImg(https://segmentfault.com/img/remote/1460000019070847?w=750&h=300); 場景:Redis面試 showImg(http...
閱讀 1062·2021-11-24 10:27
閱讀 3337·2021-11-18 10:02
閱讀 2396·2021-11-16 11:45
閱讀 3161·2021-11-15 18:10
閱讀 821·2021-09-22 15:23
閱讀 1529·2019-08-30 15:53
閱讀 3021·2019-08-30 13:20
閱讀 1666·2019-08-30 12:53