原文出處: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ù)寫(xiě)入內(nèi)存的同時(shí),異步的慢慢的將數(shù)據(jù)寫(xiě)入磁盤(pán)文件里,進(jìn)行持久化。
如果 redis 宕機(jī)重啟,自動(dòng)從磁盤(pán)上加載之前持久化的一些數(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ù),也可以歸類(lèi)到高可用的一個(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ì)每條寫(xiě)入命令作為日志,以
append-only的模式寫(xiě)入一個(gè)日志文件中,在 redis 重啟的時(shí)候,可以通過(guò)回放 AOF 日志中的寫(xiě)入指令來(lái)重新構(gòu)建整個(gè)數(shù)據(jù)集。
通過(guò) RDB 或 AOF,都可以將 redis 內(nèi)存中的數(shù)據(jù)給持久化到磁盤(pán)上面來(lái),然后可以將這些數(shù)據(jù)備份到別的地方去,比如說(shuō)阿里云等云服務(wù)。
如果 redis 掛了,服務(wù)器上的內(nèi)存和磁盤(pán)上的數(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ì)外提供的讀寫(xiě)服務(wù),影響非常小,可以讓 redis 保持高性能,因?yàn)?redis 主進(jìn)程只需要 fork 一個(gè)子進(jìn)程,讓子進(jìn)程執(zhí)行磁盤(pán) 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模式寫(xiě)入,所以沒(méi)有任何磁盤(pán)尋址的開(kāi)銷(xiāo),寫(xiě)入性能非常高,而且文件不容易破損,即使文件尾部破損,也很容易修復(fù)。 - AOF 日志文件即使過(guò)大的時(shí)候,出現(xiàn)后臺(tái)重寫(xiě)操作,也不會(huì)影響客戶端的讀寫(xiě)。因?yàn)樵?
rewritelog 的時(shí)候,會(huì)對(duì)其中的指令進(jìn)行壓縮,創(chuàng)建出一份需要恢復(fù)數(shù)據(jù)的最小日志出來(lái)。在創(chuàng)建新日志文件的時(shí)候,老的日志文件還是照常寫(xiě)入。當(dāng)新的 merge 后的日志文件 ready 的時(shí)候,再交換新老日志文件即可。 - AOF 日志文件的命令通過(guò)非??勺x的方式進(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 開(kāi)啟后,支持的寫(xiě) QPS 會(huì)比 RDB 支持的寫(xiě) QPS 低,因?yàn)?AOF 一般會(huì)配置成每秒
fsync一次日志文件,當(dāng)然,每秒一次fsync,性能也還是很高的。(如果實(shí)時(shí)寫(xiě)入,那么 QPS 會(huì)大降,redis 性能會(huì)大大降低) - 以前 AOF 發(fā)生過(guò) bug,就是通過(guò) AOF 記錄的日志,進(jìn)行數(shù)據(jù)恢復(fù)的時(shí)候,沒(méi)有恢復(fù)一模一樣的數(shù)據(jù)出來(lái)。所以說(shuō),類(lèi)似 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í)開(kāi)啟開(kāi)啟兩種持久化方式,我們可以綜合使用 AOF 和 RDB 兩種持久化機(jī)制,用 AOF 來(lái)保證數(shù)據(jù)不丟失,作為數(shù)據(jù)恢復(fù)的第一選擇; 用 RDB 來(lái)做不同程度的冷備,在 AOF 文件都丟失或損壞不可用的時(shí)候,還可以使用 RDB 來(lái)進(jìn)行快速的數(shù)據(jù)恢復(fù)。