轉(zhuǎn)載 http://www.reibang.com/p/e94fa7340923
簡介
memcached和redis都屬于內(nèi)存(memory)鍵-值(key-value)數(shù)據(jù)庫,在設(shè)計(jì)和思想上有許多相同之處变泄,功能和應(yīng)用在很多場合(如分布式緩存服務(wù))也相似颠通。它們都從屬于數(shù)據(jù)庫解決方案中的nosql家族秘通,由于兩者都將數(shù)據(jù)存儲在內(nèi)存中蓝牲,自然而然灶泵,它們都是非常理想的緩存實(shí)現(xiàn)方案徐许。
memcached最初是由Brad Fitzpatrick于2003年開發(fā)而成含友。而redis則由Salvatore Sanfilippo于2009年創(chuàng)建,它本身也從memcached上吸取借鑒大量寶貴經(jīng)驗(yàn)教訓(xùn)钮热,被稱為“強(qiáng)化版memcached”填抬。確實(shí),redis在功能多樣性方面要勝過memcached隧期,雖然強(qiáng)大且更具靈活性痴奏,但復(fù)雜程度也比memcached更甚。
基本架構(gòu)和思想
兩者的架構(gòu)和設(shè)計(jì)思想
memcached
memcached采用客戶端-服務(wù)器(C/S)的架構(gòu)厌秒,客戶端和服務(wù)器端的通訊使用自定義的協(xié)議標(biāo)準(zhǔn),只要滿足協(xié)議格式要求擅憔,客戶端Library可以用任何語言實(shí)現(xiàn)鸵闪。
從用戶的角度來說,服務(wù)器維護(hù)了一個鍵-值關(guān)系的數(shù)據(jù)表暑诸,服務(wù)器之間相互獨(dú)立蚌讼,互相之間不共享數(shù)據(jù)也不做任何通訊操作辟灰。也就是說,memcached本身不支持分布式擴(kuò)展篡石〗胬客戶端需要知道所有的服務(wù)器,并自行負(fù)責(zé)管理數(shù)據(jù)在各個服務(wù)器間的分配凰萨。
在服務(wù)器端继控,內(nèi)部的數(shù)據(jù)存儲,使用基于Slab的內(nèi)存管理方式胖眷,有利于減少內(nèi)存碎片和頻繁分配銷毀內(nèi)存所帶來的開銷武通。各個Slab按需動態(tài)分配一個page的內(nèi)存(和4Kpage的概念不同,這里默認(rèn)page為1M)珊搀,page內(nèi)部按照不同slab class的尺寸再劃分為內(nèi)存chunk供服務(wù)器存儲KV鍵值對使用冶忱。
memcached的基本應(yīng)用模型:
redis
redis的基本應(yīng)用模式和上圖memcached的基本相似,不難發(fā)現(xiàn)網(wǎng)上到處都是關(guān)于redis是否可以完全替代memcached使用的問題境析。
redis內(nèi)部的數(shù)據(jù)結(jié)構(gòu)最終也會落實(shí)到key-value對應(yīng)的形式囚枪,不過從暴露給用戶的數(shù)據(jù)結(jié)構(gòu)來看,要比memcached豐富劳淆,除了標(biāo)準(zhǔn)的通常意義的鍵值對链沼,redis還支持List,Set憔儿, Hashes忆植,Sorted Set等數(shù)據(jù)結(jié)構(gòu)。
基本命令
memcached的命令或者說通訊協(xié)議非常簡單谒臼,server所支持的命令基本就是對特定key的添加朝刊,刪除,替換蜈缤,原子更新拾氓,讀取等,具體包括 set, get, add, replace, append, inc/dec 等等底哥。
memcached的通訊協(xié)議包括文本格式和二進(jìn)制格式咙鞍,用于滿足簡單網(wǎng)絡(luò)客戶端工具(如telnet)和對性能要求更高的客戶端的不同需求。
redis的命令在kv(string類型)上提供與memcached類似的基本操作趾徽,在其它數(shù)據(jù)結(jié)構(gòu)上也支持基本類似的操作(當(dāng)然還有這些數(shù)據(jù)結(jié)構(gòu)所特有的操作续滋,如set的union,list的pop等)而支持更多的數(shù)據(jù)結(jié)構(gòu)孵奶,在一定程度上也就意味著更加廣泛的應(yīng)用場合
除了多種數(shù)據(jù)結(jié)構(gòu)的支持疲酌,redis相比memcached還提供了許多額外的特性,比如subscribe/publish命令,以支持發(fā)布/訂閱模式這樣的通知機(jī)制等等朗恳,這些額外的特性同樣有助于拓展它的應(yīng)用場景湿颅。
redis的客戶端-服務(wù)器通訊協(xié)議完全采用文本格式(在將來可能的服務(wù)器間通訊會采用二進(jìn)制格式)。
事務(wù)
redis通過multi / watch / exec等命令可以支持事務(wù)的概念粥诫,原子性的執(zhí)行一批命令油航。在2.6以后的版本中由于添加了對script腳本的支持,而腳本固有的是以transaction事務(wù)的方式執(zhí)行的怀浆,并且更加易于使用谊囚,所以不排除將來取消multi等命令接口的可能性。
memcached的應(yīng)用模式中揉稚,除了increment/decrement這樣的原子操作命令秒啦,不存在對事務(wù)的支持。
數(shù)據(jù)備份搀玖,有效性余境,持久化等
memcached不保證存儲的數(shù)據(jù)的有效性,slab內(nèi)部基于LRU也會自動淘汰舊數(shù)據(jù)灌诅,客戶端不能假設(shè)數(shù)據(jù)在服務(wù)器端的當(dāng)前狀態(tài)芳来,這應(yīng)該說是memcached的feature設(shè)定,用戶不必太多關(guān)心或者自己管理數(shù)據(jù)的淘汰更新工作猜拾,當(dāng)然是否適合你的應(yīng)用即舌,取決于具體的需求,它也可能成為你需要精確自行控制cache生命周期的一個障礙挎袜。
memcached也不做數(shù)據(jù)的持久化工作顽聂,但是有許多基于memcached協(xié)議的項(xiàng)目實(shí)現(xiàn)了數(shù)據(jù)的持久化,例如memcache DB使用BerkeleyDB進(jìn)行數(shù)據(jù)存儲盯仪,但本質(zhì)上它已經(jīng)不是一個cache server紊搪,而只是一個兼容memcached的協(xié)議key-valueData Store了
redis可以以master-slave的方式配置服務(wù)器,slave節(jié)點(diǎn)對數(shù)據(jù)進(jìn)行replica備份全景,slave節(jié)點(diǎn)也可以充當(dāng)read only的節(jié)點(diǎn)分擔(dān)數(shù)據(jù)讀取的工作
redis內(nèi)建支持兩種持久化方案耀石,snapshot快照和AOF增量Log方式“只疲快照顧名思義就是隔一段時間將完整的數(shù)據(jù)dump下來存儲在文件中滞伟。AOF增量Log則是記錄對數(shù)據(jù)的修改操作(實(shí)際上記錄的就是每個對數(shù)據(jù)產(chǎn)生修改的命令本身),兩種方案可以并存炕贵,也各有優(yōu)缺點(diǎn)梆奈,具體參見http://redis.io/topics/persistence
以上Redis的數(shù)據(jù)備份持久化方案等,如果不需要称开,為了提高性能鉴裹,也完全可以Disable
性能
memcached
memcached自身并不主動定期檢查和標(biāo)記哪些數(shù)據(jù)需要被淘汰,只有當(dāng)再次讀取相關(guān)數(shù)據(jù)時才檢查時間戳,或者當(dāng)內(nèi)存不夠使用需要主動淘汰數(shù)據(jù)時進(jìn)一步檢查LRU數(shù)據(jù)径荔。
redis
redis為了減少大量小數(shù)據(jù)CMD操作的網(wǎng)絡(luò)通訊時間開銷 RTT (Round Trip Time),支持pipeline和script技術(shù)脆霎。
所謂的pipeline就是支持在一次通訊中总处,發(fā)送多個命令給服務(wù)器批量執(zhí)行,帶來的代價是服務(wù)器端需要更多的內(nèi)存來緩存查詢結(jié)果睛蛛。
redis內(nèi)嵌了LUA解析器鹦马,可以執(zhí)行l(wèi)ua腳本,腳本可以通過eval等命令直接執(zhí)行忆肾,也可以使用script load等方式上傳到服務(wù)器端的script cache中重復(fù)使用荸频。
這兩種方式都可以有效地減少網(wǎng)絡(luò)通訊開銷,增加數(shù)據(jù)吞吐率客冈。
對于KV的操作旭从,memcached和redis都支持multiple的get和set命令(memcached的multiple set命令貌似只在二進(jìn)制的協(xié)議中支持),這同樣有利于性能的提升场仲。
實(shí)際性能方面和悦,網(wǎng)上有很多測試比較,給出的結(jié)果各不相同渠缕,這無疑和各種測試的測試用例鸽素,測試環(huán)境,和測試時具體使用的客戶端Library實(shí)現(xiàn)有關(guān)亦鳞。但是總體看下來馍忽,比較靠譜的結(jié)論是在kv類操作上,兩者的性能接近燕差,memcached的結(jié)構(gòu)更加簡單遭笋,理論上應(yīng)該會略微快一些。
集群
memcached的服務(wù)器端互相完全獨(dú)立谁不,客戶端通常通過對鍵值應(yīng)用hash算法決定數(shù)據(jù)的分區(qū)坐梯,為了減少服務(wù)器的增減對hash結(jié)果的影響,導(dǎo)致大面積的緩存失效刹帕,多數(shù)客戶端實(shí)現(xiàn)了一致性hash算法吵血。
redis計(jì)劃在服務(wù)器端內(nèi)建對集群的支持,在此之前偷溺,同樣可以認(rèn)為每個redis服務(wù)器實(shí)例相互之間是完全獨(dú)立的蹋辅,需要依靠客戶端處理分區(qū)算法和可用服務(wù)器列表管理的工作。
redis官方推薦的用于sharding的客戶端程序庫是Twitter的開源項(xiàng)目Twemproxy挫掏, Twemproxy同時支持Memcached和Redis的文本通訊協(xié)議侦另。
需要注意的是,redis的許多命令在集群環(huán)境下是不能正確運(yùn)行的,例如set的交集褒傅,以及跨節(jié)點(diǎn)的事務(wù)操作等等弃锐,因?yàn)槟壳暗膔edis集群設(shè)計(jì),根本目標(biāo)也就是服務(wù)器之間互相匯報一下存活狀態(tài)殿托,以及對數(shù)據(jù)做榮譽(yù)備份平衡負(fù)載等而已霹菊,本質(zhì)上對數(shù)據(jù)的跨節(jié)點(diǎn)操作并不提供任何額外支持,所以在數(shù)據(jù)服務(wù)的層面上來說支竹,各個服務(wù)器依舊是完全獨(dú)立的旋廷。
這些操作如果一定要實(shí)現(xiàn),當(dāng)然可以通過客戶端代碼來實(shí)現(xiàn)(效率有多高且不說)礼搁,類似的問題memcached集群當(dāng)然也會遇上饶碘,但是原本memcached就不支持復(fù)雜的操作和數(shù)據(jù)類型,許多運(yùn)算邏輯原本就是由客戶端代碼或應(yīng)用程序自己處理的馒吴。
如何選擇
何時應(yīng)該使用memcached
相對memcached而言扎运,redis的面世時間更晚且具備更多功能,因此開發(fā)人員通常將其視為默認(rèn)性首選方案募书。不過有兩類特殊場景仍然是memcached的一家天下绪囱。首先就是對小型靜態(tài)數(shù)據(jù)進(jìn)行緩存處理,最具代表性的例子就是HTML代碼片段莹捡。memcached的內(nèi)部內(nèi)存管理機(jī)制雖然不像redis的那樣復(fù)雜鬼吵,但卻更具實(shí)際效率——這是因?yàn)閙emcached在處理元數(shù)據(jù)時所消耗的內(nèi)存資源相對更少。作為memcached所支持的惟一一種數(shù)據(jù)類型篮赢,字符串非常適合用于保存那些只需要進(jìn)行讀取操作的數(shù)據(jù)齿椅,因?yàn)樽址旧頍o需進(jìn)行進(jìn)一步處理。
除此之外启泣,memcached在橫向擴(kuò)展方面也比redis更具優(yōu)勢涣脚。由于其在設(shè)計(jì)上的思路傾向以及相對更為簡單的功能設(shè)置,memcached在實(shí)現(xiàn)擴(kuò)展時的難度比redis低得多寥茫。不過根據(jù)我們了解到的情況遣蚀,目前已經(jīng)有多種經(jīng)過測試且切實(shí)有效的方案能夠?qū)edis擴(kuò)展至多臺服務(wù)器之上,而其即將發(fā)布的3.0版本(感興趣的朋友可以點(diǎn)擊此處查看其候選版本說明)將包含專門針對橫向擴(kuò)展場景的內(nèi)置集群化機(jī)制纱耻。
何時應(yīng)該使用redis
除非大家需要考慮某種限定性條件(例如處理傳統(tǒng)應(yīng)用程序)對于memcached的特殊依賴性芭梯,或者自己的實(shí)際用例屬于前面提到的兩類場景中的一種,否則請直接選擇redis并加以運(yùn)用弄喘。憑借著redis所帶來的卓越緩存方案玖喘,我們將擁有強(qiáng)大的處理能力——例如對緩存內(nèi)容及持久性進(jìn)行細(xì)節(jié)調(diào)整的能力——以及出色的整體執(zhí)行效率。
redis幾乎在緩存管理工作中的每一個側(cè)面都表現(xiàn)出顯而易見的優(yōu)越性蘑志。這套緩存方案采用所謂數(shù)據(jù)回收機(jī)制累奈,能夠?qū)㈥惻f數(shù)據(jù)從內(nèi)存中刪除以提供新數(shù)據(jù)所必需的緩存空間贬派。memcached的數(shù)據(jù)回收機(jī)制使用的是LRU(即最低近期使用量)算法,而且往往會比較武斷地直接刪除掉與新數(shù)據(jù)體系相近的原有內(nèi)容澎媒。相比之下搞乏,redis允許用戶更為精準(zhǔn)地進(jìn)行細(xì)化控制,利用六種不同回收策略確切提高緩存資源的實(shí)際利用率戒努。redis還采用更為復(fù)雜的內(nèi)存管理與回收對象備選方案查描。
redis還能為我們帶來最大程度的靈活性空間,從而保證管理員在打理緩存對象時擁有充裕的施展平臺柏卤。在這方面,memcached將鍵名限制在250字節(jié)匀油,值也被限制在不超過1MB缘缚,且只適用于普通字符串。相比之下敌蚜,redis則將鍵名與值的最大上限各自設(shè)定為512MB桥滨,且支持二進(jìn)制格式。redis支持六種數(shù)據(jù)類型弛车,因此能夠更加智能地對數(shù)據(jù)進(jìn)行緩存處理及操作齐媒,這相當(dāng)于為應(yīng)用程序開發(fā)人員敞開了一道通往無盡可能性的大門。
相對于將對象保存為序列化字符串纷跛,redis允許開發(fā)人員以散列方式將對象域及值加以保存喻括,并利用單一鍵對其進(jìn)行管理。redis散列機(jī)制的存在保證開發(fā)人員無需經(jīng)歷獲取完整字符串贫奠、反序列化唬血、更新值、對象重新序列化并在每次值更新后利用其替代緩存內(nèi)完整字符串這一系列復(fù)雜的流程——這也意味著資源消耗量得以降低唤崭、性能表現(xiàn)迎來顯著提升拷恨。redis所支持的其它數(shù)據(jù)類型,例如lists以及sets——也可被用于實(shí)現(xiàn)更加復(fù)雜的緩存管理模式谢肾。
redis的另一大重要優(yōu)勢在于腕侄,它所保存的數(shù)據(jù)具備透明化特性,也就是說服務(wù)器能夠直接對這些數(shù)據(jù)進(jìn)行操作芦疏。redis當(dāng)中提供160多種可用命令冕杠,其中大部分用于實(shí)現(xiàn)數(shù)據(jù)處理操作并通過服務(wù)器端腳本將邏輯嵌入至數(shù)據(jù)存儲體系當(dāng)中。這些內(nèi)置命令及用戶腳本帶來了極大的靈活性優(yōu)勢眯分,足以幫助大家直接在redis內(nèi)部完成數(shù)據(jù)處理任務(wù)——而不必將數(shù)據(jù)在網(wǎng)絡(luò)中的其它專門處理系統(tǒng)之間來回移動拌汇。
redis還提供可選而且能夠具體調(diào)整的數(shù)據(jù)持久性方案,其設(shè)計(jì)目的在于在發(fā)生規(guī)劃內(nèi)停機(jī)或者計(jì)劃外故障之后對緩存內(nèi)容進(jìn)行重新引導(dǎo)弊决。雖然我們更傾向于強(qiáng)調(diào)緩存內(nèi)數(shù)據(jù)的易失性與暫時性噪舀,但將數(shù)據(jù)在磁盤中加以持久保存在某些緩存場景當(dāng)中仍然極具現(xiàn)實(shí)意義魁淳。這種機(jī)制能夠在設(shè)備重啟之后快速將保存在磁盤上的數(shù)據(jù)重新載入至緩存當(dāng)中,從而大大縮短緩存預(yù)熱周期并根據(jù)主數(shù)據(jù)存儲內(nèi)容對當(dāng)前緩存內(nèi)容進(jìn)行重新評估与倡。
最后但也同樣重要的一點(diǎn)是界逛,redis能夠提供復(fù)制功能。復(fù)制功能旨在幫助緩存體系實(shí)現(xiàn)高可用性配置方案纺座,從而在遭遇故障的情況下繼續(xù)為應(yīng)用程序提供不間斷的緩存服務(wù)息拜。很明顯,一套成熟的緩存方案應(yīng)該能夠在應(yīng)用程序發(fā)生故障時略微甚至完全不給用戶體驗(yàn)或者應(yīng)用程序性能表現(xiàn)帶來任何影響净响,而這種對緩存內(nèi)容及服務(wù)可用性的有力保障在大多數(shù)情況下也成為緩存解決方案的一大主要優(yōu)勢少欺。
小結(jié)
redis的作者Salvatore Sanfilippo曾經(jīng)對這兩種基于內(nèi)存的數(shù)據(jù)存儲系統(tǒng)進(jìn)行過比較,總體來看還是比較客觀的馋贤,現(xiàn)總結(jié)如下:
- 性能對比:由于redis只使用單核赞别,而memcached可以使用多核,所以平均每一個核上redis在存儲小數(shù)據(jù)時比memcached性能更高配乓。而在100k以上的數(shù)據(jù)中仿滔,memcached性能要高于redis,雖然redis最近也在存儲大數(shù)據(jù)的性能上進(jìn)行優(yōu)化犹芹,但是比起memcached崎页,還是稍有遜色。
- 內(nèi)存使用效率對比:使用簡單的key-value存儲的話腰埂,memcached的內(nèi)存利用率更高飒焦,而如果redis采用hash結(jié)構(gòu)來做key-value存儲,由于其組合式的壓縮盐固,其內(nèi)存利用率會高于memcached荒给。另外,memcached使用預(yù)分配的內(nèi)存池的方式刁卜,帶來一定程度的空間浪費(fèi) 并且在內(nèi)存仍然有很大空間時志电,新的數(shù)據(jù)也可能會被剔除,而redis使用現(xiàn)場申請內(nèi)存的方式來存儲數(shù)據(jù)蛔趴,不會剔除任何非臨時數(shù)據(jù) redis更適合作為存儲而不是cache挑辆。
- redis支持服務(wù)器端的數(shù)據(jù)操作:redis相比memcached來說,擁有更多的數(shù)據(jù)結(jié)構(gòu)和并支持更豐富的數(shù)據(jù)操作孝情,通常在memcached里鱼蝉,你需要將數(shù)據(jù)拿到客戶端來進(jìn)行類似的修改再set回去。這大大增加了網(wǎng)絡(luò)IO的次數(shù)和數(shù)據(jù)體積箫荡。在redis中魁亦,這些復(fù)雜的操作通常和一般的GET/SET一樣高效。所以羔挡,如果需要緩存能夠支持更復(fù)雜的結(jié)構(gòu)和操作洁奈,那么redis會是不錯的選擇间唉。
另外,貼一些前輩們使用redis的經(jīng)驗(yàn)和教訓(xùn):
- 要進(jìn)行master-slave配置利术,出現(xiàn)服務(wù)故障時可以支持切換呈野。
- 在master側(cè)禁用數(shù)據(jù)持久化,只需在slave上配置數(shù)據(jù)持久化印叁。
- 物理內(nèi)存+虛擬內(nèi)存不足被冒,這個時候dump一直死著,時間久了機(jī)器掛掉轮蜕。這個情況就是災(zāi)難昨悼。
- 當(dāng)redis物理內(nèi)存使用超過內(nèi)存總?cè)萘康?/5時就會開始比較危險了,就開始做swap,內(nèi)存碎片大跃洛。
- 當(dāng)達(dá)到最大內(nèi)存時幔戏,會清空帶有過期時間的key,即使key未到過期時間税课。
- redis與DB同步寫的問題,先寫DB痊剖,后寫redis韩玩,因?yàn)閷憙?nèi)存基本上沒有問題。