1. 程式人生 > >mysql 與快取伺服器整合的介紹(memcache+redis)

mysql 與快取伺服器整合的介紹(memcache+redis)

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

基本架構和思想

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

Memcached

Memcached是以LiveJurnal旗下Danga Interactive公司的Bard Fitzpatric為首開發的高效能分散式記憶體快取伺服器。其本質上就是一個記憶體key-value資料庫,但是不支援資料的持久化,伺服器關閉之後資料全部丟失。Memcached使用C語言開發,在大多數像Linux、BSD和Solaris等POSIX系統上,只要安裝了libevent即可使 用。在Windows下,它也有一個可用的非官方版本(http://code.jellycan.com/memcached/)。

Memcached 的客戶端軟體實現非常多,包括C/C++, PHP, Java, Python, Ruby, Perl, Erlang, Lua等。當前Memcached使用廣泛,除了LiveJournal以外還有Wikipedia、Flickr、Twitter、Youtube和 WordPress等。

在Linux等系統下,我們首先需要安裝libevent,然後從獲取原始碼,make && make install即可。預設情況下,Memcached的伺服器啟動程式會安裝到/usr/local/bin目錄下。在啟動Memcached時,我們可以為其配置不同的啟動引數。

Memcached

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

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

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

供伺服器儲存KV鍵值對使用

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還支援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的操作,這當然很大程度上源於其設計思想和精簡的架構

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

綜上來說,如果要實現類似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模式的資料備份。