一.memcache和redis的相同點:
1.都是 key-value 形式的內(nèi)存數(shù)據(jù)庫
2.都是NoSQL家族的數(shù)據(jù)管理解決方案
3.都基于同樣的key-value 數(shù)據(jù)模型
4.所有數(shù)據(jù)全部放在內(nèi)存中(這也是適用于緩存的原因)
5.性能得分不分伯仲,包括數(shù)據(jù)吞吐量和延遲等指標
6.都是成熟的棘脐、廣受開源項目歡迎的 key-value存儲系統(tǒng)
二.更適合memcached的場景:
第一種是很細碎的靜態(tài)數(shù)據(jù),如HTML代碼片段。 Memcached的內(nèi)存管理不像Redis那么復(fù)雜,所以性能更高一些,原因是Memcached 的元數(shù)據(jù)metadata更小,相對來說額外開銷就很少某残。 Memcached唯一支持的數(shù)據(jù)類型是字符串String,非常適合緩存只讀數(shù)據(jù),因為字符串不需要額外的處理圾亏。
第二個場景,是Memcached比Redis更容易水平擴展艰躺。 原因在于它的設(shè)計和和功能很簡單,Memcached更容易擴展。
三.redis相較memcached的優(yōu)勢:
1 Redis不僅僅支持簡單的k/v類型的數(shù)據(jù),同時還提供list炒事,set难礼,zset娃圆,hash等數(shù)據(jù)結(jié)構(gòu)的存儲。
2 Redis支持數(shù)據(jù)的備份蛾茉,即master-slave模式的數(shù)據(jù)備份讼呢。
3 Redis支持數(shù)據(jù)的持久化,可以將內(nèi)存中的數(shù)據(jù)保持在磁盤中谦炬,重啟的時候可以再次加載進行使用悦屏。
四.memcached相較redis的優(yōu)勢:
1) 分布式 。
2)相對應(yīng)用服務(wù)器的內(nèi)存而言键思,可以進行單點訪問础爬。
3)性能強
五.memchached和redis的內(nèi)存管理機制:
memchached:
Memcached默認使用Slab Allocation機制管理內(nèi)存,其主要思想是按照預(yù)先規(guī)定的大小吼鳞,將分配的內(nèi)存分割成特定長度的塊以存儲相應(yīng)長度的key-value數(shù)據(jù)記錄看蚜,以完全解決內(nèi)存碎片問題。Slab Allocation機制只為存儲外部數(shù)據(jù)而設(shè)計赔桌,也就是說所有的key-value數(shù)據(jù)都存儲在Slab Allocation系統(tǒng)里供炎,而Memcached的其它內(nèi)存請求則通過普通的malloc/free來申請渴逻,因為這些請求的數(shù)量和頻率決定了它們不會對整個系統(tǒng)的性能造成影響。
Slab Allocation的原理相當簡單:
它首先從操作系統(tǒng)申請一大塊內(nèi)存音诫,并將其分割成各種尺寸的塊Chunk裸卫,并把尺寸相同的塊分成組Slab Class。其中纽竣,Chunk就是用來存儲key-value數(shù)據(jù)的最小單位墓贿。每個Slab Class的大小,可以在Memcached啟動的時候通過制定Growth Factor來控制蜓氨。假定Figure 1中Growth Factor的取值為1.25聋袋,所以如果第一組Chunk的大小為88個字節(jié),第二組Chunk的大小就為112個字節(jié)穴吹,依此類推幽勒。
當Memcached接收到客戶端發(fā)送過來的數(shù)據(jù)時首先會根據(jù)收到數(shù)據(jù)的大小選擇一個最合適的Slab Class,然后通過查詢Memcached保存著的該Slab Class內(nèi)空閑Chunk的列表就可以找到一個可用于存儲數(shù)據(jù)的Chunk港令。當一條數(shù)據(jù)庫過期或者丟棄時啥容,該記錄所占用的Chunk就可以回收,重新添加到空閑列表中顷霹。
從以上過程我們可以看出Memcached的內(nèi)存管理制效率高咪惠,而且不會造成內(nèi)存碎片,但是它最大的缺點就是會導(dǎo)致空間浪費淋淀。因為每個 Chunk都分配了特定長度的內(nèi)存空間遥昧,所以變長數(shù)據(jù)無法充分利用這些空間。如下圖所示朵纷,將100個字節(jié)的數(shù)據(jù)緩存到112個字節(jié)的Chunk中炭臭,剩余的12個字節(jié)就浪費掉了。
Redis的內(nèi)存管理機制:
Redis的內(nèi)存管理主要通過源碼中zmalloc.h和zmalloc.c兩個文件來實現(xiàn)的袍辞。
Redis為了方便內(nèi)存的管理鞋仍,在分配一塊內(nèi)存之后,會將這塊內(nèi)存的大小存入內(nèi)存塊的頭部搅吁。real_ptr是redis調(diào)用malloc后返回的指針威创。redis將內(nèi)存塊的大小size存入頭部,size所占據(jù)的內(nèi)存大小是已知的似芝,為 size_t類型的長度那婉,然后返回ret_ptr板甘。當需要釋放內(nèi)存的時候党瓮,ret_ptr被傳給內(nèi)存管理程序。通過ret_ptr盐类,程序可以很容易的算出 real_ptr的值寞奸,然后將real_ptr傳給free釋放內(nèi)存呛谜。
Redis通過定義一個數(shù)組來記錄所有的內(nèi)存分配情況,這個數(shù)組的長度為ZMALLOC_MAX_ALLOC_STAT枪萄。數(shù)組的每一個元素代表當前程序所分配的內(nèi)存塊的個數(shù)隐岛,且內(nèi)存塊的大小為該元素的下標。在源碼中瓷翻,這個數(shù)組為zmalloc_allocations聚凹。 zmalloc_allocations[16]代表已經(jīng)分配的長度為16bytes的內(nèi)存塊的個數(shù)。zmalloc.c中有一個靜態(tài)變量 used_memory用來記錄當前分配的內(nèi)存總大小齐帚。所以妒牙,總的來看,Redis采用的是包裝的malloc/free对妄,相較于Memcached的內(nèi)存管理方法來說湘今,要簡單很多。
六.Redis和Memcached的集群實現(xiàn)機制:
1.Memcached的分布式存儲
Memcached本身并不支持分布式剪菱,因此只能在客戶端通過像一致性哈希這樣的分布式算法來實現(xiàn)Memcached的分布式存儲摩瞎。
下圖給出了。當客戶端向Memcached集群發(fā)送數(shù)據(jù)之前孝常,首先會通過內(nèi)置的分布式算法計算出該條數(shù)據(jù)的目標節(jié)點旗们,然后數(shù)據(jù)會直接發(fā)送到該節(jié)點上存儲。但客戶端查詢數(shù)據(jù)時构灸,同樣要計算出查詢數(shù)據(jù)所在的節(jié)點蚪拦,然后直接向該節(jié)點發(fā)送查詢請求以獲取數(shù)據(jù)冻押。
2)Redis的分布式存儲
相較于Memcached只能采用客戶端實現(xiàn)分布式存儲,Redis更偏向于在服務(wù)器端構(gòu)建分布式存儲洛巢。
A.Redis Cluster介紹:
Redis Cluster是一個實現(xiàn)了分布式且允許單點故障的Redis高級版本,它沒有中心節(jié)點稿茉,具有線性可伸縮的功能。
節(jié)點與節(jié)點之間通過二進制協(xié)議進行通信漓库,節(jié)點與客戶端之間通過ascii協(xié)議進行通信。在數(shù)據(jù)的放置策略上渺蒿,Redis Cluster將整個key的數(shù)值域分成4096個哈希槽,每個節(jié)點上可以存儲一個或多個哈希槽茂装,也就是說當前Redis Cluster支持的最大節(jié)點數(shù)就是4096善延。Redis Cluster使用的分布式算法也很簡單:crc16( key ) % HASH_SLOTS_NUMBER。
B.redis主從節(jié)點:
每個Master節(jié)點都會有對應(yīng)的兩個用于冗余的Slave節(jié)點城侧。這樣在整個集群中易遣,任意兩個節(jié)點的宕機都不會導(dǎo)致數(shù)據(jù)的不可用。當Master節(jié)點退出后嫌佑,集群會自動選擇一個Slave節(jié)點成為新的Master節(jié)點豆茫。
七.數(shù)據(jù)持久化
1.memcached是不支持數(shù)據(jù)持久化,數(shù)據(jù)被放在內(nèi)存中,一旦關(guān)閉或者其他原因服務(wù)掛點,數(shù)據(jù)會丟失.
2.redis支持持久化
Redis雖然是基于內(nèi)存的存儲系統(tǒng),但是它本身是支持內(nèi)存數(shù)據(jù)的持久化的屋摇,而且提供兩種主要的持久化策略:RDB快照和AOF日志澜薄。我們會在下文分別介紹這兩種不同的持久化策略。
2.1 Redis?的快照
Redis支持將當前數(shù)據(jù)的快照存成一個數(shù)據(jù)文件的持久化機制摊册,即RDB快照肤京。Redis借助了fork命令的copy on write機制。在生成快照時茅特,將當前進程fork出一個子進程忘分,然后在子進程中循環(huán)所有的數(shù)據(jù),將數(shù)據(jù)寫成為RDB文件白修。
可以通過Redis的save指令來配置RDB快照生成的時機妒峦,比如可以配置當10分鐘以內(nèi)有100次寫入就生成快照,也可以配置當1小時內(nèi)有 1000次寫入就生成快照兵睛,也可以多個規(guī)則一起實施肯骇。這些規(guī)則的定義就在Redis的配置文件中,也可以通過Redis的CONFIG SET命令在Redis運行時設(shè)置規(guī)則祖很,不需要重啟Redis笛丙。
Redis的RDB文件不會壞掉,因為其寫操作是在一個新進程中進行的假颇,當生成一個新的RDB文件時胚鸯,Redis生成的子進程會先將數(shù)據(jù)寫到一個臨時文件中,然后通過原子性rename系統(tǒng)調(diào)用將臨時文件重命名為RDB文件笨鸡,這樣在任何時候出現(xiàn)故障姜钳,Redis的RDB文件都總是可用的。同時形耗,Redis 的RDB文件也是Redis主從同步內(nèi)部實現(xiàn)中的一環(huán)哥桥。
但可以很明顯的看到,RDB有它的不足激涤,就是一旦數(shù)據(jù)庫出現(xiàn)問題拟糕,那么RDB文件中保存的數(shù)據(jù)并不是全新的,從上次RDB文件生成到 Redis停機這段時間的數(shù)據(jù)全部丟掉了。
在某些業(yè)務(wù)下已卸,這是可以忍受的,我們也推薦這些業(yè)務(wù)使用RDB的方式進行持久化硼一,因為開啟RDB的代價并不高累澡。?
但是對于另外一些對數(shù)據(jù)安全性要求極高的應(yīng)用般贼,無法容忍數(shù)據(jù)丟失的應(yīng)用哼蛆,RDB就無能為力了,所以Redis引入了另一個重要的持久化機制:AOF日志肥矢。
2.2 Redis?的AOF日志
AOF日志的全稱是append only file甘改,從名字上就能看出來灭抑,它是一個追加寫入的日志文件。
與一般數(shù)據(jù)庫的binlog不同的是忘嫉,AOF文件是可識別的純文本庆冕,它的內(nèi)容就是一個個 的Redis標準命令劈榨。當然鞋既,并不是發(fā)送發(fā)Redis的所有命令都要記錄到AOF日志里面,只有那些會導(dǎo)致數(shù)據(jù)發(fā)生修改的命令才會追加到AOF文件跌前。
那么每一條修改數(shù)據(jù)的命令都生成一條日志陡舅,那么AOF文件是不是會很大?答案是肯定的
AOF文件會越來越大茎芋,所以Redis又提供了一個功能蜈出,叫做AOF rewrite铡原。其功能就是重新生成一份AOF文件,新的AOF文件中一條記錄的操作只會有一次只泼,而不像一份老文件那樣请唱,可能記錄了對同一個值的多次操作过蹂。其生成過程和RDB類似,也是fork一個進程孽惰,直接遍歷數(shù)據(jù),寫入新的AOF臨時文件勋功。在寫入新文件的過程中库说,所有的寫操作日志還是會寫到原來老的 AOF文件中潜的,同時還會記錄在內(nèi)存緩沖區(qū)中。當重完操作完成后信不,會將所有緩沖區(qū)中的日志一次性寫入到臨時文件中抽活。然后調(diào)用原子性的rename命令用新的 AOF文件取代老的AOF文件锰什。
AOF是一個寫文件操作丁逝,其目的是將操作日志寫到磁盤上霜幼,所以它也同樣會遇到寫操作的5個流程罪既。
寫操作的流程:
1)客戶端向服務(wù)端發(fā)送寫操作(數(shù)據(jù)在客戶端的內(nèi)存中)
2)數(shù)據(jù)庫服務(wù)端接收到寫請求的數(shù)據(jù)(數(shù)據(jù)在服務(wù)端的內(nèi)存中)
3)服務(wù)端調(diào)用write(2) 這個系統(tǒng)調(diào)用萝衩,將數(shù)據(jù)往磁盤上寫(數(shù)據(jù)在系統(tǒng)內(nèi)存的緩沖區(qū)中)
4)操作系統(tǒng)將緩沖區(qū)中的數(shù)據(jù)轉(zhuǎn)移到磁盤控制器上(數(shù)據(jù)在磁盤緩存中)
5)磁盤控制器將數(shù)據(jù)寫到磁盤的物理介質(zhì)中(數(shù)據(jù)真正落到磁盤上)
那么寫AOF的操作安全性又有多高呢没咙。實際上 這是可以設(shè)置的祭刚,在Redis中對AOF調(diào)用write(2)寫入后墙牌,何時再調(diào)用fsync將其寫到磁盤上,通過appendfsync選項來控制捉捅,下面 appendfsync的三個設(shè)置項棒口,安全強度逐漸變強辜膝。
1)appendfsync no
當設(shè)置appendfsync為no的時候,Redis不會主動調(diào)用fsync去將AOF日志內(nèi)容同步到磁盤茎毁,所以這一切就完全依賴于操作系統(tǒng)的調(diào)試了七蜘。對大多數(shù)Linux操作系統(tǒng)墙懂,是每30秒進行一次fsync垒在,將緩沖區(qū)中的數(shù)據(jù)寫到磁盤上扔亥。
2)appendfsync everysec
當設(shè)置appendfsync為everysec的時候旅挤,Redis會默認每隔一秒進行一次fsync調(diào)用粘茄,將緩沖區(qū)中的數(shù)據(jù)寫到磁盤秕脓。但是當這一次的 fsync調(diào)用時長超過1秒時。Redis會采取延遲fsync的策略芙贫,再等一秒鐘磺平。也就是在兩秒后再進行fsync拐辽,這一次的fsync就不管會執(zhí)行多 長時間都會進行俱诸。這時候由于在fsync時文件描述符會被阻塞,所以當前的寫操作就會阻塞赶诊。所以結(jié)論就是甫何,在絕大多數(shù)情況下遇伞,Redis會每隔一秒進行一 次fsync。在最壞的情況下巍耗,兩秒鐘會進行一次fsync操作炬太。這一操作在大多數(shù)數(shù)據(jù)庫系統(tǒng)中被稱為group commit驯耻,就是組合多次寫操作的數(shù)據(jù),一次性將日志寫到磁盤霎迫。
3)appednfsync always
當設(shè)置appendfsync為always時,每一次寫操作都會調(diào)用一次fsync瓤帚,這時數(shù)據(jù)是最安全的戈次,當然筒扒,由于每次都會執(zhí)行fsync霎肯,所以其性能也會受到影響榛斯。
八.Redis和Memcached整體對比
1)性能對比:由于Redis只使用單核驮俗,而Memcached可以使用多核,所以平均每一個核上Redis在存儲小數(shù)據(jù)時比Memcached性能更高搪柑。而在100k以上的數(shù)據(jù)中工碾,Memcached性能要高于Redis百姓,雖然Redis最近也在存儲大數(shù)據(jù)的性能上進行優(yōu)化,但是比起 Memcached旬迹,還是稍有遜色奔垦。
2)內(nèi)存使用效率對比:使用簡單的key-value存儲的話尸疆,Memcached的內(nèi)存利用率更高,而如果Redis采用hash結(jié)構(gòu)來做key-value存儲犯眠,由于其組合式的壓縮,其內(nèi)存利用率會高于Memcached兆衅。redis不僅僅有key-value存儲結(jié)構(gòu),也有其他的存儲結(jié)構(gòu).
3)Redis支持服務(wù)器端的數(shù)據(jù)操作:Redis相比Memcached來說羡亩,擁有更多的數(shù)據(jù)結(jié)構(gòu)和并支持更豐富的數(shù)據(jù)操作危融,通常在Memcached 里吉殃,你需要將數(shù)據(jù)拿到客戶端來進行類似的修改再set回去。這大大增加了網(wǎng)絡(luò)IO的次數(shù)和數(shù)據(jù)體積瓦灶。在Redis中贼陶,這些復(fù)雜的操作通常和一般的 GET/SET一樣高效。所以碉怔,如果需要緩存能夠支持更復(fù)雜的結(jié)構(gòu)和操作禁添,那么Redis會是不錯的選擇老翘。