memcached分佈式原理與實現

memcached分佈式原理與實現

0x01 概況

1.1 什麼是memcached

memcached是一個分佈式,開源的數據存儲引擎。php

memcached是一款高性能的分佈式內存緩存服務器,經過減小查詢次數來抵消沉重緩慢的數據集或API調用、提升應用響應速度、提升可擴展性。ios

在高併發的場景下, 大量的讀/寫請求涌向數據庫, 此時磁盤IO將成爲瓶頸, 從而致使太高的響應延遲, 所以緩存應運而生.git

image

Memcached的工做方式是將關鍵詞和他們對應的值(最大能達到1MB)保存在一個關聯矩陣中(好比哈希表),延展和分佈在大量的虛擬服務器中。github

固然不管是單機緩存仍是分佈式緩存都有其適用場景和優缺點, 最多見的有redis和memcached. 本文主要是介紹memcached.redis

1.2 緩存介紹 - 計算機體系緩存

硬盤 --> 內存 --> 三級緩存 --> 二級緩存 --> 一級緩存算法

image

1.3 緩存介紹 - 緩存應用系統

首先訪問較快的存儲介質, 若是命中且未生效則返回內容. 若是命中或失效則訪問較慢的存儲介質將內容返回同時更新緩存.docker

image

1.4 memcached特色

特色 描述
協議簡單 它是基於文本行的協議,直接經過telnet在memcached服務器上可進行存取數據操做
基於libevent事件處理 異步I/O, 基於事件的單進程和單線程, 使用libevent做爲事件處理機制;
內置內存存儲方式, 非持久性存儲 全部數據都保存在內存中,存取數據比硬盤快,當內存滿後,經過LRU算法自動刪除不使用的緩存,但沒有考慮數據的容災問題,重啓服務,全部數據會丟失。
分佈式 各個memcached服務器之間互不通訊,各自獨立存取數據,不共享任何信息。服務器並不具備分佈式功能,分佈式部署取決於memcache客戶端。

0x02 安裝與使用

2.1 如何啓動-源碼安裝

# 安裝依賴包
apt-get install libevent-dev

#安裝Memcached
wget http://memcached.org/latest
tar -zxvf memcached-1.x.x.tar.gz
cd memcached-1.x.x
./configure && make && make test && sudo make install

#啓動memcached
memcached -p 11211 -d -u root -P /tmp/memcached.pid
複製代碼

-P是表示使用TCP,默認端口爲11211 -d表示後臺啓動一個守護進程(daemon) -u表示指定root用戶啓動,默認不能用root用戶啓動 -P表示進程的pid存放地點,此處「p」爲大寫「P」 -l,後面跟IP地址,手工指定監聽IP地址,默認全部IP都在監聽 -m後面跟分配內存大小,以MB爲單位,默認爲64M -c最大運行併發鏈接數,默認爲1024 -f 塊大小增加因子,默認是1.25 -M 內存耗盡時返回錯誤,而不是刪除項,即不用LRU算法 在64位系統中,會報libevent-1.4.so.2文件沒法找到,解決辦法是把32位目錄裏的同名文件連接至64位目錄中,即像windows那樣創建快捷方式。 Shell > /usr/local/lib/libevent-1.4.so.2 /usr/lib64/libevent-1.4.so.2 啓動後若是發現沒有端口在監聽,是由於命動命令時帶pid參數的「p」是大寫「P」,你可能寫成小寫了。數據庫

2.2 如何啓動-docker安裝

// 運行一個內存限制爲1024MB的容器:

sudo docker run -name csphere-memcached -m 1024m -d -p 11211:11211 memcached:alpine
複製代碼

能夠查看Memcached:latest 使用的 Dockerfile, 來獲取 memcached在debian下的安裝方法windows

2.3 如何使用

分類 方法 描述
set 添加一個新條目到memcached或是用新的數據替換替換掉已存在的條目
add 當KEY不存在的狀況下,它向memcached存數據,不然,返回NOT_STORED響應
replace 當KEY存在的狀況下,它纔會向memcached存數據,不然返回NOT_STORED響應
cas 改變一個存在的KEY值 ,但它還帶了檢查的功能
append 在這個值後面插入新值
prepend 在這個值前面插入新值
get 取單個值 ,從緩存中返回數據時,將在第一行獲得KEY的名字,flag的值和返回的value長度,真正的數據在第二行,最後返回END,如KEY不存在,第一行就直接返回END
get_multi 一次性取多個值
delete
# 清空memcache數據 

telnet 10.27.5.71 11211    
flush_all    
quit //退出telnet
複製代碼

2.4 php使用memcached

yum -y install libmemcached.x86_64 libmemcached-devel.x86_64
 
cd /usr/src
git clone https://github.com/php-memcached-dev/php-memcached.git
cd php-memcached/
git checkout php7
/alidata/server/php/bin/phpize
./configure --with-php-config=/alidata/server/php/bin/php-config
make
make install
複製代碼

2.5 管理與性能監控

能夠經過命令行直接管理與監控也可經過nagios等監控軟件進行監控 命令行:緩存

// 若是在啓動時指定了IP及端口號,這裏要做相應改動,鏈接成功後命令 
telnet 127.0.0.1 11211
複製代碼
命令 描述
stats 統計memcached的各類信息
stats reset 從新統計數據
stats slabs 顯示slabs信息,能夠詳細看到數據的分段存儲狀況
stats items 顯示slab中的item數目
stats cachedump 1 0 列出slabs第一段裏存的KEY值
set/get 保存/獲取數據
STAT evictions 0 表示要騰出新空間給新的item而移動的合法item數目

0x03 架構原理與分析

3.1 內存算法

Memcached利用slab allocation機制來分配和管理內存,它按照預先規定的大小,將分配的內存分割成特定長度的內存塊,再把尺寸相同的內存塊分紅組,數據在存放時,根據鍵值 大小去匹配slab大小,找就近的slab存放,因此存在空間浪費現象。

傳統的內存管理方式是,使用完經過malloc分配的內存後經過free來回收內存,這種方式容易產生內存碎片並下降操做系統對內存的管理效率

Memcached的內存管理制效率高,並且不會形成內存碎片,可是它最大的缺點就是會致使空間浪費。由於每一個 Chunk都分配了特定長度的內存空間,因此變長數據沒法充分利用這些空間。如圖二所示,將100個字節的數據緩存到128個字節的Chunk中,剩餘的28個字節就浪費掉了。

image

如何避免內存浪費

  • 預先計算出應用存入的數據大小,或把同一業務類型的數據存入一個Memcached服務器中,確保存入的數據大小相對均勻,這樣就能夠減小對內存的浪費
  • 在啓動時指定「-f"參數,能在某種程度上控制內存組之間的大小差別
    • 在應用中使用Memcached時,一般能夠不從新設置這個參數,使用默認值1.25進行部署
    • 若是想優化Memcached對內存的使用,能夠考慮從新計算數據的預期平均長度,調整這個參數來得到合適的設置值

3.2 刪除機制(緩存策略)

Memcached的緩存策略是**LRU(最近最少使用)**加上到期失效策略。當你在memcached內存儲數據項時,你有可能會指定它在緩存的失效時間,默認爲永久。當memcached服務器用完分配的內時,失效的數據被首先替換,而後也是最近未使用的數據。在LRU中,memcached使用的是一種Lazy Expiration策略,本身不會監控存入的key/vlue對是否過時,而是在獲取key值時查看記錄的時間戳,檢查key/value對空間是否過時,這樣可減輕服務器的負載。

當空間佔滿時

  • 使用LRU算法來分配空間,刪除最近最少使用的key/value對
  • 若是不使用LRU的話, 在啓動參數上加入」-M」, 內存耗盡時,會返回報錯信息

3.3 分佈式概述

memcached不相互通訊,那麼memcached是如何實現分佈式的呢?

memcached的分佈式實現主要依賴客戶端的實現.

當數據到達客戶端, 客戶端實現的算法會根據」鍵」來決定保存的memcached服務器. 服務器選定後, 命令他保存數據. 取的時候也同樣, 客戶端根據」鍵」選擇服務器, 使用保存時候的相同算法就能保存選中和存的時候相同的服務器.

也就是說,存取數據分二步走,第一步,選擇服務器,第二步存取數據。

使用什麼算法選擇服務器呢?

client 使用Hash算法來完成數據分散存儲.
複製代碼

3.4 分佈式算法(Hash算法)

當向memcached集羣存入/取出key/value時,memcached客戶端程序根據必定的算法計算存入哪臺服務器,而後再把key/value值存到此服務器中。也就是說,存取數據分二步走,第一步,選擇服務器,第二步存取數據。

經常使用的算法有兩種: 餘數計算分散法 和 一致性Hash算法.

3.4.1 餘數計算分散法

  • 標準的memcached分佈式算法
CRC($key)%N
複製代碼

客戶端首先根據key來計算CPC, 而後結果對服務器取模獲得memcached服務器節點

  • 被匹配到的服務器沒法鏈接時
    • rehash: 嘗試將鏈接的次數加到key後面, 從新hash
  • 添加/移除服務器
    • 餘數計算分散發至關簡單,數據分散也很優秀
    • 幾乎全部的緩存都會失效, 緩存重組的代價至關的大。
  • 權重不易實現

3.4.2 一致性hash算法

將server的hash值分配至0~2^32的圓環上, 用一樣的方法求出存儲數值鍵的hash值並映射到圓上. 而後從數據映射到的位置開始順時針查找, 將數據存放至找到的第一臺服務器上. 若是超過0~2^32還找不到, 則將數據存放至第一臺服務器.

image

若是新添/刪除一臺server, 在一致性hash算法下會有什麼影響?

image

如圖, 新添/刪除server時, 只在圓上增長服務器的逆時針方向的第一臺服務器上的鍵會受到影響。

優化一致性hash算法

  • 通常的一致性hash算法最大限度的抑制了鍵的從新分配, 而且有的實現方式還採用了虛擬節點的思想
  • 服務器的映射地點的分佈很是的不均勻, 致使數據訪問傾斜, 大量的key被映射到同一臺服務器上.
    • 虛擬節點: 每臺機器計算出多個hash值, 每一個值對應環上的一個節點位置
    • key的映射方式不變, 就多了層從虛擬節點到再映射到物理機的過程

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

image

3.5 Hash算法的衡量指標

3.5.1 是單調性(Monotonicity)
單調性是指若是已經有一些內容經過哈希分派到了相應的緩衝中,又有新的緩衝加入到系統中。哈希的結果應可以保證原有已分配的內容能夠被映射到新的緩衝中去,而不會被映射到舊的緩衝集合中的其餘緩衝區。
複製代碼
3.5.2 平衡性
平衡性是指哈希的結果可以儘量分佈到全部的緩衝中去,這樣可使得全部的緩衝空間都獲得利用。
複製代碼

hash 算法並非保證絕對的平衡

0x04 常見問題

4.1 memcached與redis的區別?

對比點 memcached redis
數據結構 單一(存儲數據的類型都是String字符串類型) 豐富(String、List、Set、Sortedset、Hash)
內存使用率 使用簡單的key-value存儲,Memcached的內存利用率更高 Redis採用hash結構來作key-value存儲,因爲其組合式的壓縮,其內存利用率會高於Memcached
持久化 不能夠 能夠(能夠把數據隨時存儲在磁盤上)
數據同步 不能夠 能夠
多核 可使用多核(多線程) 單核
數據大小 單個key(變量)存放的數據有1M的限制 單個key(變量)存放的數據有1GB的限制
計算能力 自己有必定的計算功能
  • Redis在存儲小數據時比Memcached性能更高
  • 在100k以上的數據中,Memcached性能要高於Redis
  • memcached增長了網絡IO的次數和數據體積

memcached和redis對過時數據的處理

Redis是懶處理,對有有效期的數據會作有效期的標識,在指定時間會對有過時時間的數據作處理。隨機取出一部分數據,檢查是否有過時數據,若是過時數據超過25/100,則反覆此過程

4.2 memcache爲何快?

它使用libevent,能夠應付任意數量打開的鏈接(使用epoll,而非poll),使用非阻塞網絡IO,分佈式散列對象到不一樣的服務器,查詢複雜度是O(1)。

4.3 Memcache緩存命中率?

緩存命中率 = get_hits/cmd_get * 100%

4.4 Memcache集羣實現

一致性Hash

0x05 總結

a. 在軟件工程的項目實戰中, 常常會遇到時間/空間的權衡, 緩存是權衡中被研究出的一種典型的技術, 而memcached又是此類技術中的佼佼者.

b. 在高併發環境下,大量的讀、寫請求涌向數據庫,此時磁盤IO將成爲瓶頸,從而致使太高的響應延遲,所以緩存應運而生。

c. 本文在理解緩存基本概念的狀況下介紹了memcached的分佈式算法實現原理

相關文章
相關標籤/搜索