Memcached與Redis對比及其優劣分析


國外討論

本文主要總結緩存Redis和Memcached的區別,總結之前先參考外國知乎上的一篇問答:《Is memcached a dinosaur in comparison to Redis?》,為了方便今后查閱,將部分語句翻譯記錄一下:

  • You should not care too much about performances. Redis is faster per core with small values, but memcached is able to use multiple cores with a single executable and TCP port without help from the client. Also memcached is faster with big values in the order of 100k. Redis recently improved a lot about big values (unstable branch) but still memcached is faster in this use case. The point here is: nor one or the other will likely going to be your bottleneck for the query-per-second they can deliver.

    沒有必要過多的關心性能,因為二者的性能都已經足夠高了。由於Redis只使用單核,而Memcached可以使用多核,所以在比較上,平均每一個核上Redis在存儲小數據時比Memcached性能更高。而在100k以上的數據中,Memcached性能要高於Redis,雖然Redis最近也在存儲大數據的性能上進行優化,但是比起Memcached,還是稍有遜色。說了這么多,結論是,無論你使用哪一個,每秒處理請求的次數都不會成為瓶頸。(比如瓶頸可能會在網卡)

  • You should care about memory usage. For simple key-value pairs memcached is more memory efficient. If you use Redis hashes, Redis is more memory efficient. Depends on the use case.

    如果要說內存使用效率,使用簡單的key-value存儲的話,Memcached的內存利用率更高,而如果Redis采用hash結構來做key-value存儲,由於其組合式的壓縮,其內存利用率會高於Memcached。當然,這和你的應用場景和數據特性有關。

  • You should care about persistence and replication, two features only available in Redis. Even if your goal is to build a cache it helps that after an upgrade or a reboot your data are still there.

    如果你對數據持久化和數據同步有所要求,那么推薦你選擇Redis,因為這兩個特性Memcached都不具備。即使你只是希望在升級或者重啟系統后緩存數據不會丟失,選擇Redis也是明智的。

  • You should care about the kind of operations you need. In Redis there are a lot of complex operations, even just considering the caching use case, you often can do a lot more in a single operation, without requiring data to be processed client side (a lot of I/O is sometimes needed). This operations are often as fast as plain GET and SET. So if you don’t need just GEt/SET but more complex things Redis can help a lot (think at timeline caching).

    當然,最后還得說到你的具體應用需求。Redis相比Memcached來說,擁有更多的數據結構和並支持更豐富的數據操作,通常在Memcached里,你需要將數據拿到客戶端來進行類似的修改再set回去。這大大增加了網絡IO的次數和數據體積。在Redis中,這些復雜的操作通常和一般的GET/SET一樣高效。所以,如果你需要緩存能夠支持更復雜的結構和操作,那么Redis會是不錯的選擇。

下面是具體的各方面對比:

性能

Memcached是全內存的數據緩沖系統,Redis雖然支持數據的持久化,但是全內存才是其高性能的本質。作為基於內存的存儲系統來說,機器物理內存的大小就是系統能夠容納的最大數據量。如果需要處理的數據量超過了單台機器的物理內存大小,就需要構建分布式集群來擴展存儲能力。

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

集群與分布式方面

redis 和memcached都支持集群,redis支持master-slave模式,memcache可以使用一致性hash做分布式。簡單兩張圖看出區別:

Memcached本身並不支持分布式,因此只能在客戶端通過像一致性哈希這樣的分布式算法來實現Memcached的分布式存儲,關於分布式一致性哈希算法見總結:分布式一致性hash算法。當客戶端向Memcached集群發送數據之前,首先會通過內置的分布式算法計算出該條數據的目標節點,然后數據會直接發送到該節點上存儲。但客戶端查詢數據時,同樣要計算出查詢數據所在的節點,然后直接向該節點發送查詢請求以獲取數據。

相較於Memcached只能采用客戶端實現分布式存儲,Redis更偏向於在服務器端構建分布式存儲,但沒有采用一致性哈希,關於Redis集群分析見總結:Redis集群數據沒法拆分時的搭建策略。最新版本的Redis已經支持了分布式存儲功能。Redis Cluster是一個實現了分布式且允許單點故障的Redis高級版本,它沒有中心節點,具有線性可伸縮的功能。為了保證單點故障下的數據可用性,Redis Cluster引入了Master節點和Slave節點。在Redis Cluster中,每個Master節點都會有對應的兩個用於冗余的Slave節點。這樣在整個集群中,任意兩個節點的宕機都不會導致數據的不可用。當Master節點退出后,集群會自動選擇一個Slave節點成為新的Master節點。

數據類型

Redis支持的數據類型要比memcached豐富得多,Redis不僅僅支持簡單的K-V類型的數據,同時還提供String,List,Set,Hash,Sorted Set,pub/sub,Transactions數據結構的存儲。Redis內部使用一個redisObject對象來表示所有的key和value。

memcache支持K-V數據類型,這個V沒有類型的概念,也就意味着通過memcached取得的數據為JSON對象,並且做一次請求,會返回所有的Value數據,你需要將數據拿到客戶端來進行類似的修改再set回去,序列化再反序列化,這大大增加了網絡IO的次數和數據體積,這時候IO就是瓶頸,因為並不是所有數據都需要,同時存以及取數據時需要客戶端自己對數據進行處理。

意味着在對數據進行復雜操作方面,Redis更有優勢,因為Redis對每種類型都有獨特的操作命令,對於很多操作提升了效率。這體現了大數據方面計算向數據移動的思維。

持久性

Redis和Memcached都是將數據存放在內存中,都是內存數據庫。不過memcached還可用於緩存其他東西,例如圖片、視頻等等。

memcached把數據全部存在內存之中,斷電后會掛掉,數據不能超過內存大小;redis有部份存在硬盤上,這樣能保證數據的持久性,支持數據的持久化(RDB、AOF),而Memcached不支持持久化。

同時Redis並不是所有的數據都一直存儲在內存中的,當物理內存用完時,Redis可以將一些很久沒用到的value交換到磁盤,但memcached超過內存比例會抹掉前面的數據。redis支持數據落地持久化存儲(Redis持久化之RDB和AOF),可以將內存中的數據保持在磁盤中,重啟的時候可以再次加載進行使用。

memcache不支持數據持久存儲 ,也就是掉電就沒了。

value大小不同

memcached的簡單限制就是鍵(key)和item的限制。最大鍵長為250個字符。可以接受的儲存數據不能超過1MB,因為這是典型slab(Linux系統分配內存的一種算法) 的最大值。但是我們可以突破對key長度的限制。

修改memcached源文件。在memcached.h中定義key的長度,其代碼為:

#define KEY_MAX_LENGTH 250

更換為所需要的長度,比如:1024

#define KEY_MAX_LENGTH 1024

數據一致性方式不同

redis使用的是單線程模型,保證了數據按順序提交。

memcache需要使用cas保證數據一致性。CAS(Check and Set)是一個確保並發一致性的機制,屬於“樂觀鎖”范疇;原理很簡單:拿版本號,操作,對比版本號,如果一致就操作,不一致就放棄任何操作 cpu利用,redis單線程模型只能使用一個cpu,但是可以開啟多個redis進程。

內存管理機制

對於像Redis和Memcached這種基於內存的數據庫系統來說,內存管理的效率高低是影響系統性能的關鍵因素。傳統C語言中的malloc/free函數是最常用的分配和釋放內存的方法,但是這種方法存在着很大的缺陷:

首先對於開發人員來說不匹配的malloc和free容易造成內存泄露;其次頻繁調用會造成大量內存碎片無法回收重新利用,降低內存利用率;

然后作為系統調用,其系統開銷遠遠大於一般函數調用。所以,為了提高內存的管理效率,高效的內存管理方案都不會直接使用malloc/free調用。

Memcached默認使用Slab Allocation機制管理內存,其主要思想是按照預先規定的大小,將分配的內存分割成特定長度的塊以存儲相應長度的key-value數據記錄,以完全解決內存碎片問題。

Slab Allocation機制只為存儲外部數據而設計,也就是說所有的key-value數據都存儲在Slab Allocation系統里,而Memcached的其它內存請求則通過普通的malloc/free來申請,因為這些請求的數量和頻率決定了它們不會對整個系統的性能造成影響。

Memcacahed的Slab Allocation機制

如圖所示,它首先從操作系統申請一大塊內存,並將其分割成各種尺寸的塊Chunk,並把尺寸相同的塊分成組Slab Class。其中,Chunk就是用來存儲key-value數據的最小單位。每個Slab Class的大小,可以在Memcached啟動的時候通過制定Growth Factor來控制。假定圖中Growth Factor的取值為1.25,如果第一組Chunk的大小為88個字節,第二組Chunk的大小就為112個字節,依此類推。

當Memcached接收到客戶端發送過來的數據時首先會根據收到數據的大小選擇一個最合適的Slab Class,然后通過查詢Memcached保存着的該Slab Class內空閑Chunk的列表就可以找到一個可用於存儲數據的Chunk。當一條數據庫過期或者丟棄時,該記錄所占用的Chunk就可以回收,重新添加到空閑列表中。

從以上過程我們可以看出Memcached的內存管理制效率高,而且不會造成內存碎片,但是它最大的缺點就是會導致空間浪費。因為每個Chunk都分配了特定長度的內存空間,所以變長數據無法充分利用這些空間。比如將100個字節的數據緩存到128個字節的Chunk中,剩余的28個字節就浪費掉了。Memcached主要的cache機制是LRU(最近最少使用Least Recently Used,具體操作參考:常見頁面置換算法圖解)算法+超時失效。

Redis內存分配機制

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_allocations。zmalloc_allocations[16]代表已經分配的長度為16bytes的內存塊的個數。zmalloc.c中有一個靜態變量used_memory用來記錄當前分配的內存總大小。

所以,總的來看,Redis采用的是包裝的mallc/free,相較於Memcached的內存管理方法來說,要簡單很多


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM