redis持久化意義
- 是做災(zāi)難恢復(fù),數(shù)據(jù)恢復(fù),也可以歸類到高可用的一個(gè)環(huán)節(jié)里面去,比如你的redis整個(gè)掛了,然后redis就不可用了,你要做的事情是讓redis變得可用,盡快變得可用
- 大量的請(qǐng)求過(guò)來(lái),緩存全部無(wú)法命中,在redis里根本找不到數(shù)據(jù),這個(gè)時(shí)候就死定了,緩存雪崩問(wèn)題,所有請(qǐng)求,沒(méi)有在redis命中,就會(huì)去MySQL數(shù)據(jù)庫(kù)這種數(shù)據(jù)源頭中去找,一下子MySQL承接高并發(fā),然后就掛了
- redis持久化做得好,備份和恢復(fù)做到企業(yè)級(jí)的程度,那么即使你的redis故障了,也可以通過(guò)備份數(shù)據(jù),快速恢復(fù),一旦恢復(fù)立即對(duì)外提供服務(wù);
Redis持久化RDB
優(yōu)點(diǎn):
- RDB會(huì)生成多個(gè)數(shù)據(jù)文件,每個(gè)數(shù)據(jù)文件都代表了某一個(gè)時(shí)刻中redis的數(shù)據(jù),這種多個(gè)數(shù)據(jù)文件的方式,每個(gè)文件都代表了某一個(gè)時(shí)刻完成的數(shù)據(jù)快照,非常適合做冷備
- RDB對(duì)Redis對(duì)外提供的讀寫服務(wù),影響非常小,可以讓Redis保持高性能,因?yàn)閞edis主進(jìn)程只需要fork一個(gè)子進(jìn)程,讓子進(jìn)程執(zhí)行磁盤IO操作來(lái)進(jìn)行RDB持久化即可
- 相對(duì)于AOF持久化機(jī)制來(lái)說(shuō),直接基于RDB數(shù)據(jù)文件來(lái)重啟和恢復(fù)Redis數(shù)據(jù),更快加速
缺點(diǎn):
- 如果想要在Redis故障時(shí),盡可能少的丟失數(shù)據(jù),那么RDB沒(méi)有AOF好。一般來(lái)說(shuō),RDB數(shù)據(jù)快照文件,都是每隔5分鐘,或者更長(zhǎng)時(shí)間生成一次,這個(gè)時(shí)候就得接受一旦Redis進(jìn)程宕機(jī),那么會(huì)丟失最近5分鐘的數(shù)據(jù),這個(gè)問(wèn)題,也是RDB最大的缺點(diǎn),就是不適合做第一有限的恢復(fù)方案,如果你依賴RDB做第一優(yōu)先恢復(fù)方案,會(huì)導(dǎo)致數(shù)據(jù)丟失的比較多。
- RDB每次在fork子進(jìn)程來(lái)執(zhí)行RDB快照數(shù)據(jù)文件生成的時(shí)候,如果數(shù)據(jù)文件特別大,可能會(huì)導(dǎo)致客戶端提供的服務(wù)暫停數(shù)毫秒,甚至數(shù)秒,一般不要讓RDB的間隔太長(zhǎng),否則每次生成的RDB文件太大了,對(duì)Redis本身的性能可能會(huì)有影響的
配置:
- save 60 1000:每隔60s,如果有超過(guò)1000個(gè)key發(fā)生了變更,那么就生成一個(gè)新的dump.rdb文件,就是當(dāng)前Redis內(nèi)存中的完整地?cái)?shù)據(jù)快照 ,這個(gè)操作也被稱之為snapshotting,快照。也可以手動(dòng)調(diào)用save或者bgsave命令,同步或異步執(zhí)行RDB快照生成,save可以設(shè)置多個(gè),就是多個(gè)snapshotting檢查點(diǎn),每到一個(gè)檢查點(diǎn),就會(huì)去check一下,是否有指定的key數(shù)量發(fā)生了變更,如果有,就生成一個(gè)新的dump.rdb文件。
工作流程:
- Redis根據(jù)配置自己嘗試去生成rdb快照文件
- fork一個(gè)子進(jìn)程出來(lái)
- 子進(jìn)程嘗試將數(shù)據(jù)dump到臨時(shí)的rdb快照文件中
- 完成rdb快照文件的生成之后,就替換之前舊的快照文件,dump.rdb文件,每次生成一個(gè)新的快照,都會(huì)覆蓋之前的老快照,dump.rdb只有一個(gè)
模擬實(shí)驗(yàn):
- 通過(guò)redis-cli SHUTDOWN這種方式去掉redis,其實(shí)是一種安全退出的模式,redis在退出的時(shí)候會(huì)將內(nèi)存中的數(shù)據(jù)立即生成一份完整的rdb快照
- 用kill -9粗暴殺死redis進(jìn)程,模擬redis故障異常退出,導(dǎo)致內(nèi)存數(shù)據(jù)丟失的場(chǎng)景,這次就發(fā)現(xiàn),redis進(jìn)程異常被殺掉,數(shù)據(jù)沒(méi)有dump文件,幾條最新的數(shù)據(jù)就丟失了
Redis持久化AOF
優(yōu)點(diǎn):
- AOF可以更好地保護(hù)數(shù)據(jù)不丟失,一般AOF會(huì)每隔1秒,通過(guò)一個(gè)后臺(tái)線程執(zhí)行一次fsync操作,最多丟失1秒鐘的數(shù)據(jù),每隔1秒,就執(zhí)行一次fsync操作,保證os cache中的數(shù)據(jù)寫入磁盤中,redis進(jìn)程掛了,最多丟掉1秒鐘的數(shù)據(jù);
- AOF日志文件以Append-only模式寫入,所以沒(méi)有任何磁盤尋址的開(kāi)銷,寫入性能非常高,而且文件不容易損壞,即使文件尾部破損,也很容易修復(fù);
- AOF日志文件即使過(guò)大的時(shí)候,出現(xiàn)后臺(tái)重寫操作,也不會(huì)影響客戶端的讀寫。因?yàn)樵趓ewrite log的時(shí)候,會(huì)對(duì)其中的指導(dǎo)進(jìn)行壓縮,會(huì)創(chuàng)建出一份需要恢復(fù)數(shù)據(jù)的最小日志出來(lái)。在創(chuàng)建新日志文件的時(shí)候,老的日志文件還是照常寫入。當(dāng)新的merge后的日志文件ready的時(shí)候,再交換新老日志文件即可;
- AOF日志文件的命令通過(guò)非常刻度的方式進(jìn)行記錄,這個(gè)特性非常適合做災(zāi)難性的誤刪除的緊急恢復(fù)。比如某人不小心用flushall命令清空了所有數(shù)據(jù),只要這個(gè)時(shí)候后臺(tái)rewrite還沒(méi)有發(fā)生,那么就可以立即拷貝AOF文件,將最后一條flushall命令給刪了,然后再將該AO文件放回去,就可以通過(guò)恢復(fù)機(jī)制,自動(dòng)恢復(fù)所有數(shù)據(jù);
缺點(diǎn):
- 對(duì)于同一份數(shù)據(jù)來(lái)說(shuō),AOF日志文件通常比RDB數(shù)據(jù)快照文件更大;
- AOF開(kāi)啟后,支持的寫QPS會(huì)比RDB支持的寫QPS低,因?yàn)锳OF一般會(huì)配置成每秒fsync一次日志文件,當(dāng)然,每秒一次fsync,性能也還是很高的,如果你要保證一條數(shù)據(jù)都不丟失,也是可以的,AOF的fsync設(shè)置成每寫入一條數(shù)據(jù),fsync一次,那就完蛋了,redis的QPS效率大降;
- 做數(shù)據(jù)恢復(fù)的時(shí)候,會(huì)比較慢,還有做冷備,定期的備份,不太方便,可能要自己手寫復(fù)雜的腳本去做,做冷備不太合適;
配置:
- AOF持久化,默認(rèn)是關(guān)閉的,默認(rèn)是打開(kāi)的RDB持久化,appendonly yes,可以打開(kāi)AOF持久化機(jī)制,在生產(chǎn)環(huán)境里面,一般來(lái)說(shuō)AOF都是要打開(kāi)的,除非你說(shuō)隨便丟個(gè)幾分鐘的數(shù)據(jù)也無(wú)所謂,打開(kāi)AOF持久化機(jī)制之后,redis每次即受到一條寫命令,就會(huì)寫入日志文件中,當(dāng)然是先寫入os cache的,然后每隔一定時(shí)間再fsync一下
- 而且即使APF和RDB都開(kāi)啟了,redis重啟的時(shí)候,也是優(yōu)先通過(guò)AOF進(jìn)行數(shù)據(jù)恢復(fù)的,因?yàn)锳OF數(shù)據(jù)比較完整。
- 可以配置AOF的fsync策略,有三種策略可以選擇:
- 一種是每次寫入一條數(shù)據(jù)就執(zhí)行一次fsync;
- 一種是每隔一秒執(zhí)行一次fsync;
- 一種是不主動(dòng)執(zhí)行fsync;
① always:每次寫入一條數(shù)據(jù),立即將這個(gè)數(shù)據(jù)對(duì)應(yīng)的寫日志fsync到磁盤上去,性能非常差,吞吐量很低,確保說(shuō)redis里的數(shù)據(jù)一條都不丟,那就只能這樣了;
② mysql => 內(nèi)存策略,大量磁盤,QPS到多少,一兩k。(QPS,每秒鐘的請(qǐng)求數(shù)量 )
redis => 內(nèi)存,磁盤持久化,QPS到多少,單機(jī),一般來(lái)說(shuō),上萬(wàn)QPS沒(méi)問(wèn)題
③ everysec:每秒將os cache中的數(shù)據(jù)fsync到磁盤,這個(gè)最常用的,生產(chǎn)環(huán)境一般都這么配置,性能很高,QPS還是可以上萬(wàn)的;
④ no:僅僅redis負(fù)責(zé)將數(shù)據(jù)寫入os cache就撒手不管了,然后后面os自己會(huì)時(shí)不時(shí)有自己的策略將數(shù)據(jù)刷入磁盤,不可控了;
模擬實(shí)驗(yàn):
- kill -9殺掉Redis進(jìn)程,重新啟動(dòng)redis進(jìn)程,發(fā)現(xiàn)數(shù)據(jù)被恢復(fù)回來(lái)了,從AOF文件中恢復(fù)回來(lái)的。在appendonly.aof文件中,可以看到剛寫的日志,他們其實(shí)就是先寫入os cache的,然后1秒后才fsync到磁盤中,只有fsync到磁盤中了,才是安全的,要不然光是在os cache中,機(jī)器只要重啟,就什么都沒(méi)有了;
- redis進(jìn)程啟動(dòng)的時(shí)候,直接就會(huì)從appendonly.aof中加載所有的日志,把內(nèi)存中的數(shù)據(jù)恢復(fù)回來(lái);
AOF rewrite:
- redis中的數(shù)據(jù)其實(shí)有限的,很多數(shù)據(jù)可能會(huì)自動(dòng)過(guò)期,可能會(huì)被用戶刪除,可能會(huì)被reids用緩存清除的算法清理掉;
redis中的數(shù)據(jù)會(huì)不斷淘汰掉舊的,就一部分常用的數(shù)據(jù)會(huì)被自動(dòng)保留在redis內(nèi)存中;
所以可能很多之前的已經(jīng)被清理掉的數(shù)據(jù),對(duì)應(yīng)的寫日志還停留在AOF中,AOF日志文件就一個(gè),會(huì)不斷地膨脹,到很大很大;
所有AOF會(huì)自動(dòng)在后臺(tái)每隔一定時(shí)間做rewrite操作,比如日志里面已經(jīng)存放了針對(duì)100W數(shù)據(jù)的寫日志了;redis內(nèi)存只剩下10w;基于內(nèi)存中當(dāng)前的10w數(shù)據(jù)構(gòu)建一套最新的日志,到AOF中,覆蓋之前的老日志,確保AOF日志文件不會(huì)過(guò)大,保持跟redis內(nèi)存數(shù)據(jù)量一致; - 在redis.conf中,可以配置rewrite策略:
auto-aof-rewrite-percentage 100
auto-aof-rewrite-min-size 64mb
比如說(shuō)上一次AOF rewrite之后,是128mb;然后就會(huì)接著128mb繼續(xù)寫AOF的日志,如果發(fā)現(xiàn)增長(zhǎng)的比例,超過(guò)了之前的100%,256mb,就可能會(huì)去觸發(fā)一次rewrite;但是此時(shí)還要去跟min-size,64mb去比較,256mb>64mb,才會(huì)去觸發(fā)rewrite
比如說(shuō)上一次AOF rewrite之后,是128mb;
然后就會(huì)接著128mb繼續(xù)寫AOF的日志,如果發(fā)現(xiàn)增長(zhǎng)的比例,超過(guò)了之前的100%,256mb,就可能會(huì)去觸發(fā)一次rewrite;
但是此時(shí)還要去跟min-size,64mb去比較,256mb>64mb,才會(huì)去觸發(fā)rewrite
工作流程:
- redis fork一個(gè)子進(jìn)程;
- 子進(jìn)程基于當(dāng)前內(nèi)存中的數(shù)據(jù),構(gòu)建日志,開(kāi)始往一個(gè)新的臨時(shí)的AOF文件中寫入日志;
- redis主進(jìn)程,接收到client新的寫操作之后,在內(nèi)存中寫入日志,同時(shí)新的日志也繼續(xù)寫入舊的AOF文件;
- 子進(jìn)程寫完新的日志文件之后,reids主進(jìn)程將內(nèi)存中的新日志再次追加到新的AOF文件中;
- 用新的日志文件替換掉舊的日志文件;
RDB VS AOF
區(qū)別:
- RDB:可以做冷備,生成多個(gè)文件,每個(gè)文件都代表了某一個(gè)時(shí)刻的完整的數(shù)據(jù)快照;
AOF:也可以做冷備,只有一個(gè)文件,但是你可以,每隔一定時(shí)間,去copy一份這個(gè)文件出來(lái); - RDB:每次寫,都是直接寫redis內(nèi)存,只是在一定的時(shí)候,才會(huì)將數(shù)據(jù)寫入磁盤中;
AOF:每次都是要寫文件的,雖然可以快速寫入os cache中,但是還是有一定的時(shí)間開(kāi)銷的,速度肯定比RDB策略慢一些; - AOF:存放的指令日志,做數(shù)據(jù)恢復(fù)的時(shí)候,其實(shí)是要回放和執(zhí)行所有的指令日志,來(lái)恢復(fù)出來(lái)內(nèi)存中的所有數(shù)據(jù)的;
RDB:就是一份數(shù)據(jù)文件,恢復(fù)的時(shí)候,直接加載到內(nèi)存中即可;
同時(shí)工作:
- 如果RDB在執(zhí)行snapshotting操作,那么redis不會(huì)執(zhí)行AOF rewrite;如果redis再執(zhí)行AOF rewrite,那么就不會(huì)執(zhí)行RDB snapshotting;
- 如果RDB在執(zhí)行snapshotting操作,此時(shí)用戶執(zhí)行BGREWRITEAOF命令,那么等RDB快照生成之后,才回去執(zhí)行AOF rewrite;
- 同時(shí)有RDB snapshot文件和AOF日志文件,那么redis重啟的時(shí)候,會(huì)優(yōu)先使用AOF進(jìn)行數(shù)據(jù)恢復(fù),因?yàn)槠渲械娜罩靖暾?/li>
Redis主從架構(gòu)
主從核心機(jī)制
- redis采用異步方式復(fù)制數(shù)據(jù)到slave節(jié)點(diǎn),不過(guò)Redis2.8開(kāi)始,slave node會(huì)周期性地確認(rèn)自己每次復(fù)制的數(shù)據(jù)量;
- 一個(gè)master node是可以配置多個(gè)slave node的;
- slave node也可以連接其他的slave node;
- slave node做復(fù)制的時(shí)候,是不會(huì)block master node的正常工作的;
- slave node在做復(fù)制的時(shí)候,也不會(huì)block對(duì)自己的查詢操作,他會(huì)用舊的數(shù)據(jù)集來(lái)提供服務(wù);但是復(fù)制完成的時(shí)候,需要?jiǎng)h除舊的數(shù)據(jù)集,加載新的數(shù)據(jù)集,這個(gè)時(shí)候就會(huì)暫停對(duì)外服務(wù)了;
- slave node主要用來(lái)進(jìn)行橫向擴(kuò)容,做讀寫分離,擴(kuò)容的slave node可以提高讀的吞吐量;
Redis哨兵模式
主要功能
- 集群監(jiān)控,負(fù)責(zé)監(jiān)控redis master和slave進(jìn)程是否正常工作;
- 消息通知,如果某個(gè)redis實(shí)例有故障,那么哨兵負(fù)責(zé)發(fā)送消息作為報(bào)警通知給管理員;
- 故障轉(zhuǎn)移,如果master node掛掉了,會(huì)自動(dòng)轉(zhuǎn)移到slave node上;
- 配置中心,如果故障轉(zhuǎn)移發(fā)生了,通知client客戶端新的master地址
分布式
- 故障轉(zhuǎn)移時(shí),判斷一個(gè)master node是宕機(jī)了,需要大部分的哨兵同意才行,涉及到了分布式的選舉的問(wèn)題;
- 即使部分哨兵節(jié)點(diǎn)掛掉了,哨兵集群還是能正常工作的,因?yàn)槿绻粋€(gè)作為高可用機(jī)制重要組成部分的故障轉(zhuǎn)移系統(tǒng)本身是單點(diǎn)的,那就很坑爹了;
核心知識(shí)
- 哨兵至少需要3個(gè)實(shí)例,來(lái)保證自己的健壯性;
- 哨兵+redis主從的部署架構(gòu),是不會(huì)保證數(shù)據(jù)零丟失的,只能保證redis集群的高可用性;
- 對(duì)于哨兵+redis主從這種復(fù)雜的部署架構(gòu),盡量在測(cè)試環(huán)境和生產(chǎn)環(huán)境,都進(jìn)行充足的測(cè)試和演練;
數(shù)據(jù)丟失
(一)異步復(fù)制
- 因?yàn)?master => slave 的復(fù)制是異步的,所以可能有部分?jǐn)?shù)據(jù)還沒(méi)有復(fù)制到slave,master就宕機(jī)了,此時(shí)這些部分?jǐn)?shù)據(jù)就丟失了;
(二)腦裂
① 某個(gè)master所在機(jī)器突然脫離了正常的網(wǎng)絡(luò),跟其他slave機(jī)器不能連接,但是實(shí)際上master還運(yùn)行著;
② 此時(shí)哨兵可能就會(huì)認(rèn)為master宕機(jī)了,然后開(kāi)啟選舉,將其他slave切換成了master;
③ 這個(gè)時(shí)候,集群里就會(huì)有兩個(gè)master,也就是所謂的腦裂;
④ 此時(shí)雖然某個(gè)slave被切換成了master,但是可能client還沒(méi)來(lái)得及切換到新的master,還繼續(xù)寫向舊的master的數(shù)據(jù)可能也丟失了;
⑤ 因此舊master再次恢復(fù)的時(shí)候,會(huì)被作為一個(gè)slave掛到新的master上去,自己的數(shù)據(jù)會(huì)清空,重新從新的master復(fù)制數(shù)據(jù)
(三)解決
min-salves-to-write 1
min-slaves-max-lag 10
要求至少有一個(gè)slave,數(shù)據(jù)復(fù)制和同步的延遲不能超過(guò)10秒
如果說(shuō)一旦所有的slave,數(shù)據(jù)復(fù)制和同步的延遲都超過(guò)了10秒鐘,那么這個(gè)時(shí)候,master你就不會(huì)再接收任何請(qǐng)求了;
上面兩個(gè)配置可以減少異步復(fù)制和腦裂導(dǎo)致的數(shù)據(jù)丟失;
- 減少異步復(fù)制的數(shù)據(jù)丟失
有了min-slaves-max-lag這個(gè)配置,就可以確保說(shuō),一旦slave復(fù)制數(shù)據(jù)和ack延時(shí)太長(zhǎng),就認(rèn)為可能master宕機(jī)后損失的數(shù)據(jù)太多了,那么就拒絕寫請(qǐng)求,這樣可以把master宕機(jī)時(shí)由于部分?jǐn)?shù)據(jù)未同步到slave導(dǎo)致的數(shù)據(jù)丟失降低的可控范圍內(nèi)
- 減少腦裂的數(shù)據(jù)丟失
如果一個(gè)master出現(xiàn)腦裂,跟其他slave丟了連接,那么上面兩個(gè)配置就可以確保說(shuō),如果不能繼續(xù)給指定數(shù)量的slave發(fā)送數(shù)據(jù),而且slave超過(guò)10秒沒(méi)有給自己ack消息,那么就直接拒絕客戶端的寫請(qǐng)求;
這樣腦裂后的舊master就不會(huì)接受client的新數(shù)據(jù),也就避免了數(shù)據(jù)丟失;
上面的配置就確保了,如果跟任何一個(gè)slave丟了連接,在10秒后發(fā)現(xiàn)沒(méi)有slave給自己ack,那么就拒絕新的寫請(qǐng)求;
因此在腦裂場(chǎng)景下,最多就丟失10秒的數(shù)據(jù)
底層原理
(一)sdown和odown兩種失敗狀態(tài)轉(zhuǎn)換機(jī)制
-
- sdown是主觀宕機(jī),就一個(gè)哨兵如果自己覺(jué)得一個(gè)master宕機(jī)了,那么就是主觀宕機(jī);
sdown達(dá)成的條件很簡(jiǎn)單,如果一個(gè)哨兵ping一個(gè)master,超過(guò)了is-master-down-milliseconds指定的毫秒數(shù)之后,就主觀認(rèn)為master宕機(jī);
- sdown是主觀宕機(jī),就一個(gè)哨兵如果自己覺(jué)得一個(gè)master宕機(jī)了,那么就是主觀宕機(jī);
- odown是客觀宕機(jī),如果quorum數(shù)量的哨兵都覺(jué)得一個(gè)master宕機(jī)了,那么就是客觀宕機(jī);
sdown和odown轉(zhuǎn)換的條件很簡(jiǎn)單,如果一個(gè)哨兵在指定時(shí)間內(nèi),收到了quorum指定數(shù)量的其他哨兵也認(rèn)為那個(gè)master是sdown了,那么就認(rèn)為是odown了,客觀認(rèn)為master宕機(jī);
(二)哨兵集群的自動(dòng)發(fā)現(xiàn)機(jī)制
哨兵互相之間的發(fā)現(xiàn),是通過(guò)redis的pub/sub系統(tǒng)實(shí)現(xiàn)的,每個(gè)哨兵都會(huì)往 _sentinel_:hello 這個(gè)channel里發(fā)送一個(gè)消息,這時(shí)候所有其他哨兵都可以消費(fèi)到這個(gè)消息,并感知到其他的哨兵的存在;
每隔兩秒鐘,每隔哨兵都會(huì)往自己監(jiān)控的某個(gè)master+slaves對(duì)應(yīng)的_sentinel_:hello channel 里發(fā)送一個(gè)消息,內(nèi)容是自己的host、ip和runid還有對(duì)這個(gè)master的監(jiān)控配置;
每個(gè)哨兵也會(huì)去監(jiān)聽(tīng)自己監(jiān)控的每個(gè)master+slaves對(duì)應(yīng)的_sentinel_:hello channel,然后去感知到同樣在監(jiān)聽(tīng)這個(gè)master+slaves的其他哨兵的存在;
每個(gè)哨兵還會(huì)跟其他哨兵交換對(duì)master的監(jiān)控配置,互相進(jìn)行監(jiān)控配置的同步;
(三)slave => master選舉算法
-
- 如果一個(gè)master被認(rèn)為odown了,而且majority燒餅都允許了主備切換,那么某個(gè)哨兵就會(huì)執(zhí)行主備切換操作,此時(shí)首先要選舉一個(gè)slave來(lái),會(huì)考慮slave的一些信息:
① 跟master斷開(kāi)連接的時(shí)長(zhǎng);
② slave優(yōu)先級(jí);
③ 復(fù)制offset;
④ run id;
- 如果一個(gè)master被認(rèn)為odown了,而且majority燒餅都允許了主備切換,那么某個(gè)哨兵就會(huì)執(zhí)行主備切換操作,此時(shí)首先要選舉一個(gè)slave來(lái),會(huì)考慮slave的一些信息:
- 如果一個(gè)slave跟master斷開(kāi)連接已經(jīng)超過(guò)了down-after-milliseconds的10倍,外加master宕機(jī)的時(shí)長(zhǎng),那么slave就會(huì)被認(rèn)為不適合選舉為master
(down-after-milliseconds * 10)+milliseconds_since_master_is_in_SDOWN_state - 接下來(lái)會(huì)對(duì)slave進(jìn)行排序
① 按照slave優(yōu)先級(jí)進(jìn)行排序,slave priority 越低,優(yōu)先級(jí)就越高;
② 如果slave priority相同,那么看replica offset,哪個(gè)slave復(fù)制了越多的數(shù)據(jù),offset越靠后,優(yōu)先級(jí)就越高;
③ 如果上面兩個(gè)條件都相同,那么選擇一個(gè)run id比較小的那個(gè)slave;
瓶頸
- 如果你的數(shù)據(jù)量很少,主要是承載高并發(fā)高性能的場(chǎng)景,比如你的緩存一般就幾個(gè)G,單機(jī)足夠了;
- replication,一個(gè)master,多個(gè)slave,要幾個(gè)slave跟你的要求的讀吞吐量有關(guān)系,然后自己搭建一個(gè)sentinal集群,去保證redis主從架構(gòu)的高可用性,就可以了;
Reids cluster
介紹
cluster
- 自動(dòng)將數(shù)據(jù)進(jìn)行分片,每個(gè)master上放一部分?jǐn)?shù)據(jù);
- 提供內(nèi)置的高可用支持,部分master不可用時(shí),還是可以繼續(xù)工作的;
cluster端口
- 每個(gè)redis要開(kāi)放兩個(gè)端口號(hào),比如一個(gè)是6379,另外一個(gè)就是加10000的端口號(hào),比如16379;
- 16379端口號(hào)是用來(lái)進(jìn)行節(jié)點(diǎn)間通信的,也就是cluster bus的東西,集群總線。cluster bus的通信,用來(lái)進(jìn)行故障檢測(cè),配置更新,故障轉(zhuǎn)移授權(quán);
cluster bus用了另一種二進(jìn)制的協(xié)議,主要用于節(jié)點(diǎn)間進(jìn)行高效的數(shù)據(jù)交換,占用更少的網(wǎng)絡(luò)帶寬和處理時(shí)間;
hash slot算法
- redis cluster有固定的16384個(gè)hash slot,對(duì)每個(gè)key計(jì)算CRC16值,然后對(duì)16384取模,可以獲取key對(duì)應(yīng)的hash slot;
redis cluster中每個(gè)master都會(huì)持有部分slot,比如有3個(gè)master,那么可能每個(gè)master持有5000多個(gè)hash slot - hash slot讓node的增加和一處很簡(jiǎn)單,增加一個(gè)master,就將其他的master的hash slot移動(dòng)部分過(guò)去,減少一個(gè)master,就將它的hash slot移動(dòng)到其他master上去;
移動(dòng)hash slot的成本是非常低的;
客戶端的api,可以對(duì)指定的數(shù)據(jù),讓他們走同一個(gè)hash slot,通過(guò)hash tag來(lái)實(shí)現(xiàn);
核心原理(節(jié)點(diǎn)間的內(nèi)部通信機(jī)制)
基礎(chǔ)通信原理
(一)節(jié)點(diǎn)間采取gossip協(xié)議進(jìn)行通信
-
- 跟集中式不同,不是將集群元數(shù)據(jù)(節(jié)點(diǎn)信息,故障,等等)集中存儲(chǔ)在某個(gè)節(jié)點(diǎn)上,而是互相之間不斷通信,保持整個(gè)集群所有節(jié)點(diǎn)的數(shù)據(jù)是完整的;
- 集中式:
好處在于,元數(shù)據(jù)的更新和讀取,時(shí)效性非常好,一旦元數(shù)據(jù)出現(xiàn)了變更,立即就更新到集中式的存儲(chǔ)中,其他節(jié)點(diǎn)讀取的時(shí)候立即就可以感知到;
不好在于,所有的元數(shù)據(jù)的更新壓力全部集中在一個(gè)地方,可能會(huì)導(dǎo)致元數(shù)據(jù)的存儲(chǔ)有壓力;
- gossip:
好處在于:元數(shù)據(jù)的更新比較分散,不是集中在一個(gè)地方,更新請(qǐng)求會(huì)陸陸續(xù)續(xù),打到所有節(jié)點(diǎn)上去更新,有一定的延時(shí),降低了壓力;
缺點(diǎn):元數(shù)據(jù)更新有延時(shí),可能導(dǎo)致集群的一些操作會(huì)有一些滯后;
(二)10000端口
-
- 每個(gè)節(jié)點(diǎn)都有一個(gè)專門用于節(jié)點(diǎn)間通信的端口,就是自己提供服務(wù)的端口號(hào)+10000,比如7001,那么用于節(jié)點(diǎn)間通信的就是17001端口;
- 每個(gè)節(jié)點(diǎn)每隔一段時(shí)間都會(huì)往另外幾個(gè)節(jié)點(diǎn)發(fā)送ping信息,同時(shí)其他幾個(gè)節(jié)點(diǎn)接收到ping之后返回pong
(三)交換的信息
-
- 故障信息,節(jié)點(diǎn)的增加和移除,hash clot信息,等等;
gossip協(xié)議
- gossip協(xié)議包含多種消息,包括ping、pong、meet、fail等;
- meet:某個(gè)節(jié)點(diǎn)發(fā)送meet給新加入的節(jié)點(diǎn),讓新節(jié)點(diǎn)加入集群中,然后新節(jié)點(diǎn)就會(huì)開(kāi)始與其他節(jié)點(diǎn)進(jìn)行通信;
redis-trib.rb add-node命令:其實(shí)內(nèi)部就是發(fā)送了一個(gè)gossip meet消息,給新加入的節(jié)點(diǎn),通知那個(gè)節(jié)點(diǎn)去加入我們的集群; - ping:每個(gè)節(jié)點(diǎn)都會(huì)頻繁給其他節(jié)點(diǎn)發(fā)送ping,其中包含自己的狀態(tài)還有自己維護(hù)的集群元數(shù)據(jù),互相通過(guò)ping交換元數(shù)據(jù);
每個(gè)節(jié)點(diǎn)每秒都會(huì)頻繁發(fā)送ping給其他的集群,ping,頻繁的互相之間交換數(shù)據(jù),互相進(jìn)行元數(shù)據(jù)的更新; - pong:返回ping和meet,包含自己的狀態(tài)和其他信息,也可以用于信息廣播和更新;
- fail:某個(gè)節(jié)點(diǎn)判斷另一個(gè)節(jié)點(diǎn)fail之后,就發(fā)送fail給其他節(jié)點(diǎn),通知其他節(jié)點(diǎn),指定的節(jié)點(diǎn)宕機(jī)了;
ping消息深入
- ping很頻繁,而且要攜帶一些元數(shù)據(jù),所以可能會(huì)加重網(wǎng)絡(luò)負(fù)擔(dān);
每個(gè)節(jié)點(diǎn)每秒會(huì)執(zhí)行10次ping,每次會(huì)選擇5個(gè)最久沒(méi)有通信的其他節(jié)點(diǎn) - 當(dāng)然如果發(fā)現(xiàn)某個(gè)節(jié)點(diǎn)通信延時(shí)達(dá)到了cluster_node_timeout/2,那么立即發(fā)送ping,避免數(shù)據(jù)交換延時(shí)過(guò)長(zhǎng),落后的時(shí)間太長(zhǎng)了;
- 所以cluster_node_timeout可以調(diào)節(jié),如果調(diào)節(jié)比較大,那么會(huì)降低發(fā)送頻率;
所以每次ping,一個(gè)是帶上自己節(jié)點(diǎn)的信息,還有就是帶上1/10其他節(jié)點(diǎn)的信息,發(fā)送出去,進(jìn)行數(shù)據(jù)交換;
至少包含3個(gè)其他節(jié)點(diǎn)的信息,最多包含【總節(jié)點(diǎn)-2】個(gè)其他節(jié)點(diǎn)信息;
Redis回收算法
介紹
- redis是會(huì)在數(shù)據(jù)達(dá)到一定程度之后,超過(guò)了一個(gè)最大的限度之后,就會(huì)將數(shù)據(jù)進(jìn)行一定的清理,從內(nèi)存中清理掉一些數(shù)據(jù);
- redis默認(rèn)情況下就是使用LRU策略的,因?yàn)閮?nèi)存是有限的;
- LRU:Least Recently Used,最近最少使用算法;
將最近一段時(shí)間內(nèi),最少使用的一些數(shù)據(jù),給干掉。比如說(shuō)有一個(gè)key,在最近一個(gè)小時(shí)內(nèi),只被訪問(wèn)了一次,還有一個(gè)key在最近一個(gè)小時(shí)內(nèi),被訪問(wèn)了一萬(wàn)次
緩存清理設(shè)置
- maxmemory,設(shè)置redis用來(lái)存放數(shù)據(jù)的最大的內(nèi)存大小,一旦超出這個(gè)內(nèi)存大小之后,就會(huì)立即使用LRU算法清理掉部分?jǐn)?shù)據(jù);
- 對(duì)于64bit的機(jī)器,如果maxmemory設(shè)置為0,那么就默認(rèn)不限制內(nèi)存的使用,直到耗盡機(jī)器中所有的內(nèi)存為止;
- maxmemory-policy,可以設(shè)置內(nèi)存達(dá)到最大限制后,采取什么策略來(lái)處理;
清理策略
- noeviction:如果內(nèi)存使用達(dá)到了maxmemory,client還要繼續(xù)寫入數(shù)據(jù),那么就直接報(bào)錯(cuò)給客戶端;
- allkeys-lru:就是我們常說(shuō)的LRU算法,移除掉最少使用的那些keys對(duì)應(yīng)的數(shù)據(jù);
- volatile-lru:也是采取LRU算法,但是僅僅針對(duì)那些設(shè)置了指定存活時(shí)間(TTL)的key才會(huì)清理掉;
- allkeys-random:隨機(jī)選擇一些key來(lái)刪除掉;
- volatile-random:隨機(jī)選擇一些設(shè)置了TTL的key來(lái)刪除掉;
- volatile-ttl:移除掉部分keys,選擇那些TTL時(shí)間比較短的keys;






