Memcached 及 Redis 架構分析和比較

五柳-先生發表於2016-06-06

MemcachedRedis作為兩種Inmemorykey-value資料庫,在設計和思想方面有著很多共通的地方,功能和應用方面在很多場合下(作為分散式快取伺服器使用等也很相似,在這裡把兩者放在一起做一下對比的介紹

  

基本架構和思想

 

首先簡單介紹一下兩者的架構和設計思路

 

Memcached

 

Memcached採用客戶端-伺服器的架構,客戶端和伺服器端的通訊使用自定義的協議標準,只要滿足協議格式要求,客戶端Library可以用任何語言實現。

 

從使用者的角度來說,伺服器維護了一個鍵-值關係的資料表,伺服器之間相互獨立,互相之間不共享資料也不做任何通訊操作。客戶端需要知道所有的伺服器,並自行負責管理資料在各個伺服器間的分配。

 

在伺服器端,內部的資料儲存,使用基於Slab的記憶體管理方式,有利於減少記憶體碎片和頻繁分配銷燬記憶體所帶來的開銷。各個Slab按需動態分配一個page的記憶體(和4Kpage的概念不同,這裡預設page1M),page內部按照不同slab class的尺寸再劃分為記憶體chunk供伺服器儲存KV鍵值對使用




 

Memcached的基本應用模型如下圖所示

 


 

 

 

Redis

 

Redis的基本應用模式和上圖memcached的基本相似,不難發現網上到處都是關於redis是否可以完全替代memcached使用的問題

 

Redis內部的資料結構最終也會落實到key-Value對應的形式,不過從暴露給使用者的資料結構來看,要比memcached豐富,除了標準的通常意義的鍵值對,Redis還支援ListSet HashesSorted Set等資料結構

 

基本命令

 

Memcached的命令或者說通訊協議非常簡單,Server所支援的命令基本就是對特定key的新增,刪除,替換,原子更新,讀取等,具體包括 Set, Get, Add, Replace, Append, Inc/Dec 等等

 

Memcached的通訊協議包括文字格式和二進位制格式,用於滿足簡單網路客戶端工具(如telnet)和對效能要求更高的客戶端的不同需求

 

Redis的命令在KVString型別)上提供與Memcached類似的基本操作,在其它資料結構上也支援基本類似的操作(當然還有這些資料結構所特有的操作,如SetunionListpop等)而支援更多的資料結構,在一定程度上也就意味著更加廣泛的應用場合

 

除了多種資料結構的支援,Redis相比Memcached還提供了許多額外的特性,比如Subscribe/publish命令,以支援釋出/訂閱模式這樣的通知機制等等,這些額外的特性同樣有助於擴充它的應用場景

 

Redis的客戶端-伺服器通訊協議完全採用文字格式(在將來可能的伺服器間通訊會採用二進位制格式)

 

 

事務

 

redis通過Multi / Watch /Exec等命令可以支援事務的概念,原子性的執行一批命令。在2.6以後的版本中由於新增了對Script指令碼的支援,而指令碼固有的是以transaction事務的方式執行的,並且更加易於使用,所以不排除將來取消Multi等命令介面的可能性

 

Memcached的應用模式中,除了increment/decrement這樣的原子操作命令,不存在對事務的支援

 

資料備份,有效性,持久化等

 

memcached不保證儲存的資料的有效性,Slab內部基於LRU也會自動淘汰舊資料,客戶端不能假設資料在伺服器端的當前狀態,這應該說是MemcachedFeature設定,使用者不必太多關心或者自己管理資料的淘汰更新工作,當然是否適合你的應用,取決於具體的需求,它也可能成為你需要精確自行控制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),支援pipelinescript技術

 

  • 所謂的pipeline就是支援在一次通訊中,傳送多個命令給伺服器批量執行,帶來的代價是伺服器端需要更多的記憶體來快取查詢結果。
  • Redis內嵌了LUA解析器,可以執行lua 指令碼,指令碼可以通過eval等命令直接執行,也可以使用script load等方式上傳到伺服器端的script cache中重複使用

 

這兩種方式都可以有效地減少網路通訊開銷,增加資料吞吐率

 

對於KV的操作,MemcachedRedis都支援MultipleGetSet命令(MemcachedMultiple Set命令貌似只在二進位制的協議中支援),這同樣有利於效能的提升

 

實際效能方面,網上有很多測試比較,給出的結果各不相同,這無疑和各種測試的測試用例,測試環境,和測試時具體使用的客戶端Library實現有關。但是總體看下來,比較靠譜的結論是在kv類操作上,兩者的效能接近,Memcached的結構更加簡單,理論上應該會略微快一些。

 

 

叢集

 

memcached的伺服器端互相完全獨立,客戶端通常通過對鍵值應用Hash演算法決定資料的分割槽,為了減少伺服器的增減對Hash結果的影響,導致大面積的快取失效,多數客戶端實現了一致性hash演算法

 

Redis計劃在伺服器端內建對叢集的支援,但是目前程式碼還處於alpha階段(貌似已經Design了兩三年了?)在此之前,同樣可以認為每個Redis伺服器例項相互之間是完全獨立的,需要依靠客戶端處理分割槽演算法和可用伺服器列表管理的工作。

 


 

Redis官方推薦的用於Sharding的客戶端程式庫是Twitter的開源專案 Twemproxy, Twemproxy同時支援MemcachedRedis的文字通訊協議。

 

需要注意的是,Redis的許多命令在叢集環境下是不能正確執行的,例如set的交集,以及跨節點的事務操作等等,因為目前的Redis叢集設計,根本目標也就是伺服器之間互相彙報一下存活狀態,以及對資料做榮譽備份平衡負載等而已,本質上對資料的跨節點操作並不提供任何額外支援,所以在資料服務的層面上來說,各個伺服器依舊是完全獨立的。

 

這些操作如果一定要實現,當然可以通過客戶端程式碼來實現(效率有多高且不說),類似的問題memcached叢集當然也會遇上,但是原本memcached就不支援複雜的操作和資料型別,許多運算邏輯原本就是由客戶端程式碼或應用程式自己處理的。

 

 

MR類批處理應用

 

提供指定範圍的遍歷操作,是支援類似MapReduce這樣的批處理應用邏輯的關鍵之一,但是要在基於hash方式儲存的資料結構的基礎上提供這樣的支援並不容易(或者說要實現高效的範圍或遍歷操作並不容易)

 

Redis支援Scan操作用於遍歷資料集,這一操作基於其內部資料結構及實現的限制,可以保證在Scan開始時的所有資料都能被獲取到,但是不能保證不返回重複的資料,這需要由客戶端來檢查,或者客戶端對此無所謂。Scan操作還支援Match條件用來過濾鍵值,雖然存在一定的侷限性,例如match條件的比較是在獲取資料之後再執行的,效率是一個問題,更明顯的問題是不能保證每次scaniterate過程都能返回同樣數量的有效資料。

 

對於範圍操作,RedisOrdered Set支援在插入時指定資料的分數(Score)用於排序,而後支援在指定Score範圍內的各種操作,雖然由於不支援基於字串的或自定義的基準的Range操作,這樣的範圍操作應用起來有很大的侷限性(或者說需要滿足特定的應用模式),但是還是比沒有好了

 

Memcached核心協議本身不支援任何範圍類的操作,也沒有對遍歷操作的支援,甚至不存在官方合法的列舉所有Key的操作,這當然很大程度上源於其設計思想和精簡的架構

 

不過還是有一些相容memcached協議的伺服器實現了範圍類操作,具體格式可以參考 https://code.google.com/p/memcached/wiki/RangeOps 所建議的標準

 

此外RedisHashes資料結構,在一定程度上可以滿足獲取特定子集資料的應用邏輯需求。

 

綜上來說,如果要實現類似HBase支援的scan操作,不論是Redis還是memcached都無法做到,但是對於Redis來說,能否用於批處理類應用,不能一概而論,取決於具體的資料的格式邏輯和使用方式。通過適當的調整應用程式使用資料的方式,還是有可能在一定程度上實現對MR類批處理,或範圍查詢類應用邏輯的支援的。而對於鍵值分佈在一個較大的連續空間,數量不確定,同時又無法很好的對映為數值進而使用ordered set來處理的這樣一些資料結構,應該還是很難高效的分割槽遍歷的

轉載:http://blog.csdn.net/colorant/article/details/21089057






相關文章