redis和memcached的區別詳解

Redis 和 Memcache 都是基於內存的數據存儲系統。Memcached是高性能分佈式內存緩存服務;Redis是一個開源的key-value存儲系統。與Memcached相似,Redis將大部分數據存儲在內存中,支持的數據類型包括:字符串、哈希 表、鏈表、等數據類型的相關操做。下面咱們來進行來看一下redis和memcached的區別redis

 

Redis的做者Salvatore Sanfilippo曾經對這兩種基於內存的數據存儲系統進行過比較:數據庫

  1. Redis支持服務器端的數據操做:Redis相比Memcached來講,擁有更多的數據結構和並支持更豐富的數據操做,一般在Memcached裏,你須要將數據拿到客戶端來進行相似的修改再set回去。這大大增長了網絡IO的次數和數據體積。在Redis中,這些複雜的操做一般和通常的GET/SET同樣高效。因此,若是須要緩存可以支持更復雜的結構和操做,那麼Redis會是不錯的選擇。數組

  2. 內存使用效率對比:使用簡單的key-value存儲的話,Memcached的內存利用率更高,而若是Redis採用hash結構來作key-value存儲,因爲其組合式的壓縮,其內存利用率會高於Memcached。緩存

  3. 性能對比:因爲Redis只使用單核,而Memcached可使用多核,因此平均每個核上Redis在存儲小數據時比Memcached性能更高。而在100k以上的數據中,Memcached性能要高於Redis,雖然Redis最近也在存儲大數據的性能上進行優化,可是比起Memcached,仍是稍有遜色。安全

具體爲何會出現上面的結論,如下爲收集到的資料:服務器

一、數據類型支持不一樣網絡

與Memcached僅支持簡單的key-value結構的數據記錄不一樣,Redis支持的數據類型要豐富得多。最爲經常使用的數據類型主要由五種:String、Hash、List、Set和Sorted Set。Redis內部使用一個redisObject對象來表示全部的key和value。redisObject最主要的信息如圖所示:session

type表明一個value對象具體是何種數據類型,encoding是不一樣數據類型在redis內部的存儲方式,好比:type=string表明value存儲的是一個普通字符串,那麼對應的encoding能夠是raw或者是int,若是是int則表明實際redis內部是按數值型類存儲和表示這個字符串的,固然前提是這個字符串自己能夠用數值表示,好比:」123″ 「456」這樣的字符串。只有打開了Redis的虛擬內存功能,vm字段字段纔會真正的分配內存,該功能默認是關閉狀態的。數據結構

1)String併發

經常使用命令:set/get/decr/incr/mget等;

應用場景:String是最經常使用的一種數據類型,普通的key/value存儲均可以歸爲此類;

實現方式:String在redis內部存儲默認就是一個字符串,被redisObject所引用,當遇到incr、decr等操做時會轉成數值型進行計算,此時redisObject的encoding字段爲int。

2)Hash

經常使用命令:hget/hset/hgetall等

應用場景:咱們要存儲一個用戶信息對象數據,其中包括用戶ID、用戶姓名、年齡和生日,經過用戶ID咱們但願獲取該用戶的姓名或者年齡或者生日;

實現方式:Redis的Hash實際是內部存儲的Value爲一個HashMap,並提供了直接存取這個Map成員的接口。如圖所示,Key是用戶ID, value是一個Map。這個Map的key是成員的屬性名,value是屬性值。這樣對數據的修改和存取均可以直接經過其內部Map的Key(Redis裏稱內部Map的key爲field), 也就是經過 key(用戶ID) + field(屬性標籤) 就能夠操做對應屬性數據。當前HashMap的實現有兩種方式:當HashMap的成員比較少時Redis爲了節省內存會採用相似一維數組的方式來緊湊存儲,而不會採用真正的HashMap結構,這時對應的value的redisObject的encoding爲zipmap,當成員數量增大時會自動轉成真正的HashMap,此時encoding爲ht。

3)List

經常使用命令:lpush/rpush/lpop/rpop/lrange等;

應用場景:Redis list的應用場景很是多,也是Redis最重要的數據結構之一,好比twitter的關注列表,粉絲列表等均可以用Redis的list結構來實現;

實現方式:Redis list的實現爲一個雙向鏈表,便可以支持反向查找和遍歷,更方便操做,不過帶來了部分額外的內存開銷,Redis內部的不少實現,包括髮送緩衝隊列等也都是用的這個數據結構。

4)Set

經常使用命令:sadd/spop/smembers/sunion等;

應用場景:Redis set對外提供的功能與list相似是一個列表的功能,特殊之處在於set是能夠自動排重的,當你須要存儲一個列表數據,又不但願出現重複數據時,set是一個很好的選擇,而且set提供了判斷某個成員是否在一個set集合內的重要接口,這個也是list所不能提供的;

實現方式:set 的內部實現是一個 value永遠爲null的HashMap,實際就是經過計算hash的方式來快速排重的,這也是set能提供判斷一個成員是否在集合內的緣由。

5)Sorted Set

經常使用命令:zadd/zrange/zrem/zcard等;

應用場景:Redis sorted set的使用場景與set相似,區別是set不是自動有序的,而sorted set能夠經過用戶額外提供一個優先級(score)的參數來爲成員排序,而且是插入有序的,即自動排序。當你須要一個有序的而且不重複的集合列表,那麼能夠選擇sorted set數據結構,好比twitter 的public timeline能夠以發表時間做爲score來存儲,這樣獲取時就是自動按時間排好序的。

實現方式:Redis sorted set的內部使用HashMap和跳躍表(SkipList)來保證數據的存儲和有序,HashMap裏放的是成員到score的映射,而跳躍表裏存放的是全部的成員,排序依據是HashMap裏存的score,使用跳躍表的結構能夠得到比較高的查找效率,而且在實現上比較簡單。

二、內存管理機制不一樣

在Redis中,並非全部的數據都一直存儲在內存中的。這是和Memcached相比一個最大的區別。當物理內存用完時,Redis能夠將一些好久沒用到的value交換到磁盤。Redis只會緩存全部的key的信息,若是Redis發現內存的使用量超過了某一個閥值,將觸發swap的操做,Redis根據「swappability = age*log(size_in_memory)」計算出哪些key對應的value須要swap到磁盤。而後再將這些key對應的value持久化到磁盤中,同時在內存中清除。這種特性使得Redis能夠保持超過其機器自己內存大小的數據。固然,機器自己的內存必需要可以保持全部的key,畢竟這些數據是不會進行swap操做的。同時因爲Redis將內存中的數據swap到磁盤中的時候,提供服務的主線程和進行swap操做的子線程會共享這部份內存,因此若是更新須要swap的數據,Redis將阻塞這個操做,直到子線程完成swap操做後才能夠進行修改。當從Redis中讀取數據的時候,若是讀取的key對應的value不在內存中,那麼Redis就須要從swap文件中加載相應數據,而後再返回給請求方。 這裏就存在一個I/O線程池的問題。在默認的狀況下,Redis會出現阻塞,即完成全部的swap文件加載後纔會相應。這種策略在客戶端的數量較小,進行批量操做的時候比較合適。可是若是將Redis應用在一個大型的網站應用程序中,這顯然是沒法知足大併發的狀況的。因此Redis運行咱們設置I/O線程池的大小,對須要從swap文件中加載相應數據的讀取請求進行併發操做,減小阻塞的時間。

對於像Redis和Memcached這種基於內存的數據庫系統來講,內存管理的效率高低是影響系統性能的關鍵因素。傳統C語言中的malloc/free函數是最經常使用的分配和釋放內存的方法,可是這種方法存在着很大的缺陷:首先,對於開發人員來講不匹配的malloc和free容易形成內存泄露;其次頻繁調用會形成大量內存碎片沒法回收從新利用,下降內存利用率;最後做爲系統調用,其系統開銷遠遠大於通常函數調用。因此,爲了提升內存的管理效率,高效的內存管理方案都不會直接使用malloc/free調用。Redis和Memcached均使用了自身設計的內存管理機制,可是實現方法存在很大的差別,下面將會對二者的內存管理機制分別進行介紹。

Memcached默認使用Slab Allocation機制管理內存,其主要思想是按照預先規定的大小,將分配的內存分割成特定長度的塊以存儲相應長度的key-value數據記錄,以徹底解決內存碎片問題。Slab Allocation機制只爲存儲外部數據而設計,也就是說全部的key-value數據都存儲在Slab Allocation系統裏,而Memcached的其它內存請求則經過普通的malloc/free來申請,由於這些請求的數量和頻率決定了它們不會對整個系統的性能形成影響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個字節就浪費掉了。

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的內存管理方法來講,要簡單不少。

三、數據持久化支持

Redis雖然是基於內存的存儲系統,可是它自己是支持內存數據的持久化的,並且提供兩種主要的持久化策略:RDB快照和AOF日誌。而memcached是不支持數據持久化操做的。

 

區別總結以下

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

二、Redis不只僅支持簡單的k/v類型的數據,同時還提供list,set,hash等數據結構的存儲;

三、虛擬內存--Redis當物理內存用完時,能夠將一些好久沒用到的value 交換到磁盤;

四、過時策略--memcache在set時就指定,例如set key1 0 0 8,即永不過時。Redis能夠經過例如expire 設定,例如expire name 10;

五、分佈式--設定memcache集羣,利用magent作一主多從;redis能夠作一主多從。均可以一主一從;

六、存儲數據安全--memcache掛掉後,數據沒了;redis能夠按期保存到磁盤(持久化);

七、災難恢復--memcache掛掉後,數據不可恢復; redis數據丟失後能夠經過aof恢復;

八、Redis支持數據的備份,即master-slave模式的數據備份;

九、應用場景不同:Redis出來做爲NoSQL數據庫使用外,還能用作消息隊列、數據堆棧和數據緩存等;Memcached適合於緩存SQL語句、數據集、用戶臨時性數據、延遲查詢數據和session等。

相關文章
相關標籤/搜索