Redis和Memcache的區別

2021-10-06 22:29:52 字數 4691 閱讀 1603

redis和memcache都是基於記憶體的資料儲存系統。memcached是高效能分布式記憶體快取服務;redis是乙個開源的key-value儲存系統。與memcached類似,redis將大部分資料儲存在記憶體中,支援的資料型別包括:字串、雜湊 表、鍊錶、等資料型別的相關操作。下面我們來進行來看一下redis和memcached的區別:

redis的作者salvatore sanfilippo曾經對這兩種基於記憶體的資料儲存系統進行過比較:

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

記憶體使用效率對比:使用簡單的key-value儲存的話,memcached的記憶體利用率更高,而如果redis採用hash結構來做key-value儲存,由於其組合式的壓縮,其記憶體利用率會高於memcached。

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

以下具體講述為什麼會出現上面的結論:

與memcached僅支援簡單的key-value結構的資料記錄不同,redis支援的資料型別要豐富得多。最為常用的資料型別主要由五種:string、hash、list、set和sorted set。redis內部使用乙個redisobject物件來表示所有的key和value。redisobject最主要的資訊如圖所示:

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這種基於記憶體的資料庫系統來說,記憶體管理的效率高低是影響系統效能的關鍵因素。傳統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是不支援資料持久化操作的。

memcache和redis的區別

redis和memecache的不同在於 1 儲存方式 memecache 把資料全部存在記憶體之中,斷電後會掛掉,資料不能超過記憶體大小 redis有部份存在硬碟上,這樣能保證資料的永續性。2 資料支援型別 redis在資料支援上要比memecache多的多。3 使用底層模型不同 新版本的redi...

Redis和Memcache的區別

redis和memcache的不同點 1 儲存方式 redis和memcache都是將資料存放在記憶體中,都是記憶體資料庫。memcache把資料全部存在記憶體之中,資料不能超過記憶體大小,斷電後會掛掉,掛掉後資料不可恢復。redis可以定期儲存到磁碟 持久化 這樣能保證資料的永續性。reids若資...

Redis和Memcache的區別總結

區別 1.儲存方式不同 memcache 把資料全部存在記憶體之中,斷電後會掛掉,資料不能超過記憶體大小 redis有部分存在硬碟上,這樣能保證資料的永續性,支援資料的持久化 筆者注 有快照和aof日誌日誌兩種持久化方式,在實際應用的時候,要特別注意配置檔案快照引數,要不就很有可能伺服器頻繁滿載做d...