1. 程式人生 > 實用技巧 >分散式快取之Redis與Memcached的比較

分散式快取之Redis與Memcached的比較

一、效能

由於Redis只使用單核,而Memcached可以使用多核,所以平均每一個核上Redis儲存小資料時比Memcached效能更高。而在100k以上的資料時,Memcached效能要高於Redis,雖然Redis最近也在儲存大資料的效能上進行優化,但是比起Memcached,還是稍有遜色。

二、記憶體使用效率

使用簡單的key/value儲存的話,Memcached的記憶體利用率更高,而如果Redis採用hash結構來做key/value儲存,由於其組合方式的押送,其記憶體利用率會高於Memcached。

三、Redis支援伺服器端的資料操作

Redis相比Memcached來說,擁有更多的資料結構並支援更豐富的資料操作,通常在Memcached裡,你需要將資料拿到客戶端來進行類似的修改再set回去,序列化再反序列化,這大大增加了網路IO的次數和資料體積。在Redis中,這些複雜的操作通常和一般的get/set一樣高效。所以,如果需要快取能夠支援更復雜的結構和操作,那麼在Redis會是不錯的選擇。

與Memcached僅支援簡單的key/value結構的資料記錄不同,Redis支援的資料型別要豐富得多。最為常用得資料型別主要有5中:String、Hash、List、Set、Zset。Redis內部使用一個redisObject物件來表示所有得key和value。

四、資料備份恢復

memcached掛掉後,資料不可恢復;redis資料丟失之後可以通過aof模式備份進行恢復,Redis支援資料得備份,即master-slave主從模式得資料備份。

五、資料儲存

Redis和Memcache都是將資料存放在記憶體中,都是記憶體資料庫。不過Memcache除了簡單得key/value資料型別,還可以存放啟動東西,比如圖片、視訊等。memcache把資料全部都存放在記憶體中,斷電之後會掛掉,資料不能超過記憶體大小;Redis有部分存放在硬碟上,這樣能保證資料得永續性,支援資料得持久化(RDB、AOF),而Memcache不支援持久化。同時Redis並不是所有資料都一直儲存在記憶體中,當實體記憶體用完,Redis可以將一些很久沒用得value交換到磁碟,但memcache超過記憶體比例會抹掉前面得資料。

六、記憶體管理機制

對於像Redis和Memcached這種基於記憶體得資料庫系統來說,記憶體管理得效率高低是影響系統性能得關鍵因素。傳統C語言中得malloc/free函式是最常用得分配和釋放記憶體得方法,但是這種方法存在很大得缺陷:首先,對於開發人員來說不匹配得malloc和free容易造成記憶體洩漏;其次,頻繁呼叫會造成大量記憶體碎片無法回收重新利用,降低記憶體利用率;最後作為系統呼叫,其系統開銷遠遠大於一般函式呼叫。所以,為了提高記憶體得管理效率,高效得記憶體管理方案都不會直接使用malloc/free呼叫。
Mamcached預設使用Slab Allocation機制管理記憶體,其主要思想是按照預先規定得大小,將分配得記憶體分割成特定長度得塊以儲存相應長度得key/value得資料記錄,以完全解決記憶體碎片問題。Slab Alloction機制指揮儲存外部資料而設計,也就是說所有得key/value資料都儲存在Slab Allocation系統裡,而Memcached的其他記憶體請求則通過普通的malloc/free來申請,因為這些請求的數量和頻率決定了它們不會對整個系統的效能造成影響。

【圖片】

如圖所示,它首先從作業系統申請一大塊記憶體,並將其分割成各種尺寸的塊Chunk,並把尺寸相同的塊分成組SLab Class。其中,Chunk就是用來儲存key/value資料最小單位。每個Slab Class的大小,可以在Memcached啟動的時候通過指定Growth Factor來控制。假定圖中Growth Factor的取值未,如果第一組Chunk的大小為88個位元組,第二組Chunk的大小為112個位元組,依次類推。
當Memcached接受到客戶端發來的資料時,首先會根據收到資料的大小選擇一個合適的Slab Class,然後通過查詢Memcached儲存著該Slab Class記憶體空閒Chunk的列表就可以找到一個可用於儲存資料的Chunk。當一條資料庫過期或者丟棄時,該記錄所佔有的Chunk就可以回收,重新新增到空閒列表中。
從以上過程我們可以看出Memcached的記憶體管理效率搞,而且不會造成記憶體碎片,但是它最大的確定就是會導致空間浪費,因為每個Chunk都分配了特定長度的記憶體空間,所以變長資料無法充分利用這些空間。比如將100個位元組的資料快取到128個位元組的Chunk中,剩餘的這28個位元組就浪費掉了。Memcached主要的cache機制就是LRU演算法+超時演算法。
在這裡插入圖片描述

Redis的記憶體管理主要通過原始碼的zmalloc.h和zmalloc.c兩個檔案來實現的。Redis為了方便記憶體的管理,在分配一塊記憶體之後,會將這塊記憶體的大小存入記憶體塊的頭部。
在這裡插入圖片描述

如圖所示,real_ptr是Redis呼叫malloc後返回的指標。Redis將記憶體塊的大小Size存入頭部,size所佔據的記憶體大小是已知的,為size_t型別的長度,然後返回ret_ptr。當需要釋放記憶體的時候ret_ptr被傳給記憶體管理程式,通過ret_ptr,程式可以很容易的算出real_ptr的值,然後real_ptr傳給free釋放記憶體。
Redis通過定義一個數組來記錄所有的記憶體分配情況,這個陣列的長度為ZMALLOC_MAX_ALLOC_STAT。陣列的每一個元素代表當前程式所分配的記憶體塊的個數,且記憶體塊的大小為該元素的下標。在原始碼中,這個陣列為zmalloc_allocation。zmalloc_allocations[16]代表以及分配的長度為16bytes的記憶體塊的個數。zmalloc.c中有一個靜態變數used_memory用來記錄當前分配的記憶體總大小。所以,中的來看,Redis採用的是包裝的mallc/free,相較與Memcached的記憶體管理方法來說,要簡單很多。

七、叢集、分散式儲存

Memcached是全記憶體的資料緩衝系統,Redis雖然支援資料的持久化,但是圈記憶體畢竟才是其高效能的本質,作為基於記憶體的儲存系統來說,機器實體記憶體的大小就是系統能夠容納的最大資料量。如果需要處理的資料量超過了單臺機器的實體記憶體大小,就需要構建分散式叢集來擴充套件儲存能力。
Memcached本身不支援分散式,因此只能在客戶端通過像一致性雜湊這樣的分散式演算法來實現Memcached的分散式儲存,關於分散式一致性雜湊演算法見總結:分散式一致性hash演算法。當客戶端向Memcached叢集傳送資料之前首先會通過內建的分散式演算法計算出該條資料的目標節點,然後資料會直接傳送到該節點上儲存。但客戶端查詢資料時,同樣要計算出查詢資料所在的節點,然後直接向該節點發送查詢請求以獲取資料。
相較於Memcached只能採用客戶端實現分散式儲存,Redis更偏向於在伺服器端構建分散式儲存,但沒有采用一致性雜湊,關於Redis叢集分析見總結:分散式快取Redis之cluster叢集。最新版本的Redis一鍵支援了分散式儲存功能。Redis Cluster是一個實現了分散式且允許單點故障的Redis高階版本,它沒有中心節點,具有線性可伸縮的功能。為了保證單點故障下的資料可用性,Redis Cluster引入了Master節點和Slave節點。在Redis Cluster中,每個Master節點都會有對應的兩個用於冗餘的Slave節點。這樣在整個叢集中,任意兩個節點的宕機都不會導致資料得不可用。當Master節點退出後,叢集會自動選擇一個Slave節點成為新的Master節點。

八、Memcached支援多核多執行緒,Redis單執行緒操作