原文出處:https://github.com/doocs/advanced-java/blob/master/docs/high-concurrency/redis-persistence.md
歡迎 star 關(guān)注 GitHub 項(xiàng)目最新動(dòng)態(tài)!
面試題
redis 的持久化有哪幾種方式翎迁?不同的持久化機(jī)制都有什么優(yōu)缺點(diǎn)栋猖?持久化機(jī)制具體底層是如何實(shí)現(xiàn)的?
面試官心理分析
redis 如果僅僅只是將數(shù)據(jù)緩存在內(nèi)存里面汪榔,如果 redis 宕機(jī)了再重啟蒲拉,內(nèi)存里的數(shù)據(jù)就全部都弄丟了啊。你必須得用 redis 的持久化機(jī)制痴腌,將數(shù)據(jù)寫入內(nèi)存的同時(shí)雌团,異步的慢慢的將數(shù)據(jù)寫入磁盤文件里,進(jìn)行持久化士聪。
如果 redis 宕機(jī)重啟锦援,自動(dòng)從磁盤上加載之前持久化的一些數(shù)據(jù)就可以了,也許會(huì)丟失少許數(shù)據(jù)剥悟,但是至少不會(huì)將所有數(shù)據(jù)都弄丟灵寺。
這個(gè)其實(shí)一樣,針對(duì)的都是 redis 的生產(chǎn)環(huán)境可能遇到的一些問(wèn)題区岗,就是 redis 要是掛了再重啟略板,內(nèi)存里的數(shù)據(jù)不就全丟了?能不能重啟的時(shí)候把數(shù)據(jù)給恢復(fù)了慈缔?
面試題剖析
持久化主要是做災(zāi)難恢復(fù)叮称、數(shù)據(jù)恢復(fù),也可以歸類到高可用的一個(gè)環(huán)節(jié)中去,比如你 redis 整個(gè)掛了瓤檐,然后 redis 就不可用了赂韵,你要做的事情就是讓 redis 變得可用,盡快變得可用挠蛉。
重啟 redis祭示,盡快讓它對(duì)外提供服務(wù),如果沒(méi)做數(shù)據(jù)備份谴古,這時(shí)候 redis 啟動(dòng)了绍移,也不可用啊,數(shù)據(jù)都沒(méi)了讥电。
很可能說(shuō),大量的請(qǐng)求過(guò)來(lái)轧抗,緩存全部無(wú)法命中恩敌,在 redis 里根本找不到數(shù)據(jù),這個(gè)時(shí)候就死定了横媚,出現(xiàn)緩存雪崩問(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:RDB 持久化機(jī)制,是對(duì) redis 中的數(shù)據(jù)執(zhí)行周期性的持久化狡忙。
- AOF:AOF 機(jī)制對(duì)每條寫入命令作為日志梳虽,以
append-only
的模式寫入一個(gè)日志文件中,在 redis 重啟的時(shí)候灾茁,可以通過(guò)回放 AOF 日志中的寫入指令來(lái)重新構(gòu)建整個(gè)數(shù)據(jù)集窜觉。
通過(guò) RDB 或 AOF,都可以將 redis 內(nèi)存中的數(shù)據(jù)給持久化到磁盤上面來(lái)北专,然后可以將這些數(shù)據(jù)備份到別的地方去禀挫,比如說(shuō)阿里云等云服務(wù)。
如果 redis 掛了逗余,服務(wù)器上的內(nèi)存和磁盤上的數(shù)據(jù)都丟了特咆,可以從云服務(wù)上拷貝回來(lái)之前的數(shù)據(jù),放到指定的目錄中,然后重新啟動(dòng) redis腻格,redis 就會(huì)自動(dòng)根據(jù)持久化數(shù)據(jù)文件中的數(shù)據(jù)画拾,去恢復(fù)內(nèi)存中的數(shù)據(jù),繼續(xù)對(duì)外提供服務(wù)菜职。
如果同時(shí)使用 RDB 和 AOF 兩種持久化機(jī)制青抛,那么在 redis 重啟的時(shí)候,會(huì)使用 AOF 來(lái)重新構(gòu)建數(shù)據(jù)酬核,因?yàn)?AOF 中的數(shù)據(jù)更加完整蜜另。
RDB 優(yōu)缺點(diǎn)
RDB 會(huì)生成多個(gè)數(shù)據(jù)文件,每個(gè)數(shù)據(jù)文件都代表了某一個(gè)時(shí)刻中 redis 的數(shù)據(jù)嫡意,這種多個(gè)數(shù)據(jù)文件的方式举瑰,非常適合做冷備,可以將這種完整的數(shù)據(jù)文件發(fā)送到一些遠(yuǎn)程的安全存儲(chǔ)上去蔬螟,比如說(shuō) Amazon 的 S3 云服務(wù)上去此迅,在國(guó)內(nèi)可以是阿里云的 ODPS 分布式存儲(chǔ)上,以預(yù)定好的備份策略來(lái)定期備份 redis 中的數(shù)據(jù)旧巾。
RDB 對(duì) redis 對(duì)外提供的讀寫服務(wù)耸序,影響非常小,可以讓 redis 保持高性能鲁猩,因?yàn)?redis 主進(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 進(jì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ù)。
RDB 每次在 fork 子進(jìn)程來(lái)執(zhí)行 RDB 快照數(shù)據(jù)文件生成的時(shí)候恩溅,如果數(shù)據(jù)文件特別大隔箍,可能會(huì)導(dǎo)致對(duì)客戶端提供的服務(wù)暫停數(shù)毫秒,或者甚至數(shù)秒脚乡。
AOF 優(yōu)缺點(diǎn)
- AOF 可以更好的保護(hù)數(shù)據(jù)不丟失蜒滩,一般 AOF 會(huì)每隔 1 秒滨达,通過(guò)一個(gè)后臺(tái)線程執(zhí)行一次
fsync
操作,最多丟失 1 秒鐘的數(shù)據(jù)俯艰。 - AOF 日志文件以
append-only
模式寫入捡遍,所以沒(méi)有任何磁盤尋址的開銷,寫入性能非常高竹握,而且文件不容易破損画株,即使文件尾部破損,也很容易修復(fù)啦辐。 - AOF 日志文件即使過(guò)大的時(shí)候谓传,出現(xiàn)后臺(tái)重寫操作,也不會(huì)影響客戶端的讀寫芹关。因?yàn)樵?
rewrite
log 的時(shí)候续挟,會(huì)對(duì)其中的指令進(jìn)行壓縮,創(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
命令給刪了罪塔,然后再將該AOF
文件放回去投蝉,就可以通過(guò)恢復(fù)機(jī)制,自動(dòng)恢復(fù)所有數(shù)據(jù)征堪。 - 對(duì)于同一份數(shù)據(jù)來(lái)說(shuō)瘩缆,AOF 日志文件通常比 RDB 數(shù)據(jù)快照文件更大。
- AOF 開啟后佃蚜,支持的寫 QPS 會(huì)比 RDB 支持的寫 QPS 低庸娱,因?yàn)?AOF 一般會(huì)配置成每秒
fsync
一次日志文件,當(dāng)然谐算,每秒一次fsync
熟尉,性能也還是很高的。(如果實(shí)時(shí)寫入洲脂,那么 QPS 會(huì)大降斤儿,redis 性能會(huì)大大降低) - 以前 AOF 發(fā)生過(guò) bug,就是通過(guò) AOF 記錄的日志,進(jìn)行數(shù)據(jù)恢復(fù)的時(shí)候往果,沒(méi)有恢復(fù)一模一樣的數(shù)據(jù)出來(lái)疆液。所以說(shuō),類似 AOF 這種較為復(fù)雜的基于命令日志 / merge / 回放的方式棚放,比基于 RDB 每次持久化一份完整的數(shù)據(jù)快照文件的方式枚粘,更加脆弱一些,容易有 bug飘蚯。不過(guò) AOF 就是為了避免 rewrite 過(guò)程導(dǎo)致的 bug馍迄,因此每次 rewrite 并不是基于舊的指令日志進(jìn)行 merge 的,而是基于當(dāng)時(shí)內(nèi)存中的數(shù)據(jù)進(jìn)行指令的重新構(gòu)建局骤,這樣健壯性會(huì)好很多攀圈。
RDB 和 AOF 到底該如何選擇
- 不要僅僅使用 RDB,因?yàn)槟菢訒?huì)導(dǎo)致你丟失很多數(shù)據(jù)峦甩;
- 也不要僅僅使用 AOF赘来,因?yàn)槟菢佑袃蓚€(gè)問(wèn)題:第一,你通過(guò) AOF 做冷備凯傲,沒(méi)有 RDB 做冷備來(lái)的恢復(fù)速度更快犬辰;第二,RDB 每次簡(jiǎn)單粗暴生成數(shù)據(jù)快照冰单,更加健壯幌缝,可以避免 AOF 這種復(fù)雜的備份和恢復(fù)機(jī)制的 bug;
- redis 支持同時(shí)開啟開啟兩種持久化方式诫欠,我們可以綜合使用 AOF 和 RDB 兩種持久化機(jī)制涵卵,用 AOF 來(lái)保證數(shù)據(jù)不丟失,作為數(shù)據(jù)恢復(fù)的第一選擇; 用 RDB 來(lái)做不同程度的冷備荒叼,在 AOF 文件都丟失或損壞不可用的時(shí)候轿偎,還可以使用 RDB 來(lái)進(jìn)行快速的數(shù)據(jù)恢復(fù)。