做者:劉旭暉 Raymond 轉載請註明出處redis
Email:colorant at 163.com算法
BLOG:http://blog.csdn.net/colorant/數據庫
Memcached和Redis做爲兩種Inmemory的key-value數據庫,在設計和思想方面有着不少共通的地方,功能和應用方面在不少場合下(做爲分佈式緩存服務器使用等) 也很類似,在這裏把二者放在一塊兒作一下對比的介紹緩存
基本架構和思想服務器
首先簡單介紹一下二者的架構和設計思路網絡
Memcached數據結構
Memcached採用客戶端-服務器的架構,客戶端和服務器端的通信使用自定義的協議標準,只要知足協議格式要求,客戶端Library能夠用任何語言實現。架構
從用戶的角度來講,服務器維護了一個鍵-值關係的數據表,服務器之間相互獨立,互相之間不共享數據也不作任何通信操做。客戶端須要知道全部的服務器,並自行負責管理數據在各個服務器間的分配。分佈式
在服務器端,內部的數據存儲,使用基於Slab的內存管理方式,有利於減小內存碎片和頻繁分配銷燬內存所帶來的開銷。各個Slab按需動態分配一個page的內存(和4Kpage的概念不一樣,這裏默認page爲1M),page內部按照不一樣slab class的尺寸再劃分爲內存chunk供服務器存儲KV鍵值對使用memcached
Memcached的基本應用模型以下圖所示
Redis
Redis的基本應用模式和上圖memcached的基本類似,不難發現網上處處都是關於redis是否能夠徹底替代memcached使用的問題
Redis內部的數據結構最終也會落實到key-Value對應的形式,不過從暴露給用戶的數據結構來看,要比memcached豐富,除了標準的一般意義的鍵值對,Redis還支持List,Set, Hashes,Sorted Set等數據結構
基本命令
Memcached的命令或者說通信協議很是簡單,Server所支持的命令基本就是對特定key的添加,刪除,替換,原子更新,讀取等,具體包括 Set, Get, Add, Replace, Append, Inc/Dec 等等
Memcached的通信協議包括文本格式和二進制格式,用於知足簡單網絡客戶端工具(如telnet)和對性能要求更高的客戶端的不一樣需求
Redis的命令在KV(String類型)上提供與Memcached相似的基本操做,在其它數據結構上也支持基本相似的操做(固然還有這些數據結構所特有的操做,如Set的union,List的pop等)而支持更多的數據結構,在必定程度上也就意味着更加普遍的應用場合
除了多種數據結構的支持,Redis相比Memcached還提供了許多額外的特性,好比Subscribe/publish命令,以支持發佈/訂閱模式這樣的通知機制等等,這些額外的特性一樣有助於拓展它的應用場景
Redis的客戶端-服務器通信協議徹底採用文本格式(在未來可能的服務器間通信會採用二進制格式)
事務
redis經過Multi / Watch /Exec等命令能夠支持事務的概念,原子性的執行一批命令。在2.6之後的版本中因爲添加了對Script腳本的支持,而腳本固有的是以transaction事務的方式執行的,而且更加易於使用,因此不排除未來取消Multi等命令接口的可能性
Memcached的應用模式中,除了increment/decrement這樣的原子操做命令,不存在對事務的支持
數據備份,有效性,持久化等
memcached不保證存儲的數據的有效性,Slab內部基於LRU也會自動淘汰舊數據,客戶端不能假設數據在服務器端的當前狀態,這應該說是Memcached的Feature設定,用戶沒必要太多關心或者本身管理數據的淘汰更新工做,固然是否適合你的應用,取決於具體的需求,它也可能成爲你須要精確自行控制Cache生命週期的一個障礙
Memcached也不作數據的持久化工做,可是有許多基於memcached協議的項目實現了數據的持久化,例如memcacheDB使用BerkeleyDB進行數據存儲,但本質上它已經不是一個Cache Server,而只是一個兼容Memcached的協議key-valueData Store了
Redis能夠以master-slave的方式配置服務器,Slave節點對數據進行replica備份,Slave節點也能夠充當Read only的節點分擔數據讀取的工做
Redis內建支持兩種持久化方案,snapshot快照和AOF 增量Log方式。快照顧名思義就是隔一段時間將完整的數據Dump下來存儲在文件中。AOF增量Log則是記錄對數據的修改操做(實際上記錄的就是每一個對數據產生修改的命令自己),兩種方案能夠並存,也各有優缺點,具體參見http://redis.io/topics/persistence
以上Redis的數據備份持久化方案等,若是不須要,爲了提升性能,也徹底能夠Disable
性能
性能方面,二者都有一些本身考慮和實現
Memcached
memcached自身並不主動按期檢查和標記哪些數據須要被淘汰,只有當再次讀取相關數據時才檢查時間戳,或者當內存不夠使用須要主動淘汰數據時進一步檢查LRU數據
Redis
Redis爲了減小大量小數據CMD操做的網絡通信時間開銷 RTT (Round Trip Time),支持pipeline和script技術
這兩種方式均可以有效地減小網絡通信開銷,增長數據吞吐率
對於KV的操做,Memcached和Redis都支持Multiple的Get和Set命令(Memcached的Multiple Set命令貌似只在二進制的協議中支持),這一樣有利於性能的提高
實際性能方面,網上有不少測試比較,給出的結果各不相同,這無疑和各類測試的測試用例,測試環境,和測試時具體使用的客戶端Library實現有關。可是整體看下來,比較靠譜的結論是在kv類操做上,二者的性能接近,Memcached的結構更加簡單,理論上應該會略微快一些。
集羣
memcached的服務器端互相徹底獨立,客戶端一般經過對鍵值應用Hash算法決定數據的分區,爲了減小服務器的增減對Hash結果的影響,致使大面積的緩存失效,多數客戶端實現了一致性hash算法
Redis計劃在服務器端內建對集羣的支持,可是目前代碼還處於alpha階段(貌似已經Design了兩三年了?)在此以前,一樣能夠認爲每一個Redis服務器實例相互之間是徹底獨立的,須要依靠客戶端處理分區算法和可用服務器列表管理的工做。
Redis官方推薦的用於Sharding的客戶端程序庫是Twitter的開源項目 Twemproxy, Twemproxy同時支持Memcached和Redis的文本通信協議。
須要注意的是,Redis的許多命令在集羣環境下是不能正確運行的,例如set的交集,以及跨節點的事務操做等等,由於目前的Redis集羣設計,根本目標也就是服務器之間互相彙報一下存活狀態,以及對數據作榮譽備份平衡負載等而已,本質上對數據的跨節點操做並不提供任何額外支持,因此在數據服務的層面上來講,各個服務器依舊是徹底獨立的。
這些操做若是必定要實現,固然能夠經過客戶端代碼來實現(效率有多高且不說),相似的問題memcached集羣固然也會趕上,可是本來memcached就不支持複雜的操做和數據類型,許多運算邏輯本來就是由客戶端代碼或應用程序本身處理的。
MR類批處理應用
提供指定範圍的遍歷操做,是支持相似MapReduce這樣的批處理應用邏輯的關鍵之一,可是要在基於hash方式存儲的數據結構的基礎上提供這樣的支持並不容易(或者說要實現高效的範圍或遍歷操做並不容易)
Redis支持Scan操做用於遍歷數據集,這一操做基於其內部數據結構及實現的限制,能夠保證在Scan開始時的全部數據都能被獲取到,可是不能保證不返回重複的數據,這須要由客戶端來檢查,或者客戶端對此無所謂。Scan操做還支持Match條件用來過濾鍵值,雖然存在必定的侷限性,例如match條件的比較是在獲取數據以後再執行的,效率是一個問題,更明顯的問題是不能保證每次scan的iterate過程都能返回一樣數量的有效數據。
對於範圍操做,Redis的Ordered Set支持在插入時指定數據的分數(Score)用於排序,然後支持在指定Score範圍內的各類操做,雖然因爲不支持基於字符串的或自定義的基準的Range操做,這樣的範圍操做應用起來有很大的侷限性(或者說須要知足特定的應用模式),可是仍是比沒有好了
Memcached核心協議自己不支持任何範圍類的操做,也沒有對遍歷操做的支持,甚至不存在官方合法的列舉全部Key的操做,這固然很大程度上源於其設計思想和精簡的架構
不過仍是有一些兼容memcached協議的服務器實現了範圍類操做,具體格式能夠參考 https://code.google.com/p/memcached/wiki/RangeOps 所建議的標準
此外Redis的Hashes數據結構,在必定程度上能夠知足獲取特定子集數據的應用邏輯需求。
綜上來講,若是要實現相似HBase支持的scan操做,不管是Redis仍是memcached都沒法作到,可是對於Redis來講,可否用於批處理類應用,不能一律而論,取決於具體的數據的格式邏輯和使用方式。經過適當的調整應用程序使用數據的方式,仍是有可能在必定程度上實現對MR類批處理,或範圍查詢類應用邏輯的支持的。而對於鍵值分佈在一個較大的連續空間,數量不肯定,同時又沒法很好的映射爲數值進而使用ordered set來處理的這樣一些數據結構,應該仍是很難高效的分區遍歷的