mysql 與快取伺服器整合的介紹(memcache+redis)
Memcached和Redis作為兩種Inmemory的key-value資料庫,在設計和思想方面有著很多共通的地方,功能和應用方面在很多場合下(作為分散式快取伺服器使用等) 也很相似,在這裡把兩者放在一起做一下對比的介紹
基本架構和思想
首先簡單介紹一下兩者的架構和設計思路
Memcached
Memcached是以LiveJurnal旗下Danga Interactive公司的Bard Fitzpatric為首開發的高效能分散式記憶體快取伺服器。其本質上就是一個記憶體key-value資料庫,但是不支援資料的持久化,伺服器關閉之後資料全部丟失。Memcached使用C語言開發,在大多數像Linux、BSD和Solaris等POSIX系統上,只要安裝了libevent即可使 用。在Windows下,它也有一個可用的非官方版本(http://code.jellycan.com/memcached/)。
在Linux等系統下,我們首先需要安裝libevent,然後從獲取原始碼,make && make install即可。預設情況下,Memcached的伺服器啟動程式會安裝到/usr/local/bin目錄下。在啟動Memcached時,我們可以為其配置不同的啟動引數。
Memcached
從使用者的角度來說,伺服器維護了一個鍵-值關係的資料表,伺服器之間相互獨立,互相之間不共享資料也不做任何通訊操作。客戶端需要知道所有的伺服器,並自行負責管理資料在各個伺服器間的分配。
在伺服器端,內部的資料儲存,使用基於Slab的記憶體管理方式,有利於減少記憶體碎片和頻繁分配銷燬記憶體所帶來的開銷。各個Slab按需動態分配一個page的記憶體(和4K page的概念不同,這裡預設page為1M),page內部按照不同slab class的尺寸再劃分為記憶體chunk
Memcached的基本應用模型如下圖所示
Redis
Redis是一個開源的key-value儲存系統。與Memcached類似,Redis將大部分資料儲存在記憶體中,支援的資料型別包括:字串、雜湊 表、連結串列、集合、有序集合以及基於這些資料型別的相關操作。Redis使用C語言開發,在大多數像Linux、BSD和Solaris等POSIX系統上無需任何外部依賴就可以使用。Redis支援的客戶端語言也非常豐富,常用的計算機語言如C、C#、C++、Object-C、PHP、Python、 Java、Perl、Lua、Erlang等均有可用的客戶端來訪問Redis伺服器。當前Redis的應用已經非常廣泛,國內像新浪、淘寶,國外像 Flickr、Github等均在使用Redis的快取服務。
Redis的安裝非常方便,只需從http://redis.io/download獲取原始碼,然後make && make install即可。預設情況下,Redis的伺服器啟動程式和客戶端程式會安裝到/usr/local/bin目錄下。在啟動Redis伺服器時,我們需要為其指定一個配置檔案,預設情況下配置檔案在Redis的原始碼目錄下,檔名為redis.conf。
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技術
- 所謂的pipeline就是支援在一次通訊中,傳送多個命令給伺服器批量執行,帶來的代價是伺服器端需要更多的記憶體來快取查詢結果。
- Redis內嵌了LUA解析器,可以執行lua 指令碼,指令碼可以通過eval等命令直接執行,也可以使用script load等方式上傳到伺服器端的script cache中重複使用
這兩種方式都可以有效地減少網路通訊開銷,增加資料吞吐率
對於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的操作,這當然很大程度上源於其設計思想和精簡的架構
此外Redis的Hashes資料結構,在一定程度上可以滿足獲取特定子集資料的應用邏輯需求。
綜上來說,如果要實現類似HBase支援的scan操作,不論是Redis還是memcached都無法做到,但是對於Redis來說,能否用於批處理類應用,不能一概而論,取決於具體的資料的格式邏輯和使用方式。通過適當的調整應用程式使用資料的方式,還是有可能在一定程度上實現對MR類批處理,或範圍查詢類應用邏輯的支援的。而對於鍵值分佈在一個較大的連續空間,數量不確定,同時又無法很好的對映為數值進而使用ordered set來處理的這樣一些資料結構,應該還是很難高效的分割槽遍歷的。
關於Redis和memcache的對比:
1. Redis中,並不是所有的資料都一直儲存在記憶體中的,這是和Memcached相比一個最大的區別。
2. Redis不僅僅支援簡單的k/v型別的資料,同時還提供list,set,hash等資料結構的儲存。
3. Redis支援資料的備份,即master-slave模式的資料備份。
4. Redis支援資料的持久化,可以將記憶體中的資料保持在磁碟中,重啟的時候可以再次載入進行使用。
Redis在很多方面具備資料庫的特徵,或者說就是一個數據庫系統,而Memcached只是簡單的K/V快取
來看下Redis作者對比redis和memcache
來源:《Is memcached a dinosaur in comparison to Redis?》(相比Redis,Memcached真的過時了嗎?)
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會是不錯的選擇。
1、 Redis和Memcache都是將資料存放在記憶體中,都是記憶體資料庫。不過memcache還可用於快取其他東西,例如圖片、視訊等等。2、Redis不僅僅支援簡單的k/v型別的資料,同時還提供list,set,hash等資料結構的存儲。3、虛擬記憶體--Redis當實體記憶體用完時,可以將一些很久沒用到的value 交換到磁碟4、過期策略--memcache在set時就指定,例如set key1 0 0 8,即永不過期。Redis可以通過例如expire 設定,例如expire name 105、分散式--設定memcache叢集,利用magent做一主多從;redis可以做一主多從。都可以一主一從6、儲存資料安全--memcache掛掉後,資料沒了;redis可以定期儲存到磁碟(持久化)7、災難恢復--memcache掛掉後,資料不可恢復; redis資料丟失後可以通過aof恢復8、Redis支援資料的備份,即master-slave模式的資料備份。