redis提供了兩種持久化的方式,分別是RDB(Redis DataBase)和AOF(Append Only File)。
RDB,簡而言之,就是在不同的時(shí)間點(diǎn),將redis存儲(chǔ)的數(shù)據(jù)生成快照并存儲(chǔ)到磁盤等介質(zhì)上;
AOF,則是換了一個(gè)角度來實(shí)現(xiàn)持久化,那就是將redis執(zhí)行過的所有寫指令記錄下來,在下次redis重新啟動(dòng)時(shí),只要把這些寫指令從前到后再重復(fù)執(zhí)行一遍,就可以實(shí)現(xiàn)數(shù)據(jù)恢復(fù)了。
其實(shí)RDB和AOF兩種方式也可以同時(shí)使用,在這種情況下,如果redis重啟的話,則會(huì)優(yōu)先采用AOF方式來進(jìn)行數(shù)據(jù)恢復(fù),這是因?yàn)锳OF方式的數(shù)據(jù)恢復(fù)完整度更高。
如果你沒有數(shù)據(jù)持久化的需求,也完全可以關(guān)閉RDB和AOF方式,這樣的話,redis將變成一個(gè)純內(nèi)存數(shù)據(jù)庫,就像memcache一樣。
【聊聊redis持久化 – RDB】
RDB方式,是將redis某一時(shí)刻的數(shù)據(jù)持久化到磁盤中,是一種快照式的持久化方法。
redis在進(jìn)行數(shù)據(jù)持久化的過程中,會(huì)先將數(shù)據(jù)寫入到一個(gè)臨時(shí)文件中,待持久化過程都結(jié)束了,才會(huì)用這個(gè)臨時(shí)文件替換上次持久化好的文件。正是這種特性,讓我們可以隨時(shí)來進(jìn)行備份,因?yàn)榭煺瘴募偸峭暾捎玫摹?/p>
對(duì)于RDB方式,redis會(huì)單獨(dú)創(chuàng)建(fork)一個(gè)子進(jìn)程來進(jìn)行持久化,而主進(jìn)程是不會(huì)進(jìn)行任何IO操作的,這樣就確保了redis極高的性能。
如果需要進(jìn)行大規(guī)模數(shù)據(jù)的恢復(fù),且對(duì)于數(shù)據(jù)恢復(fù)的完整性不是非常敏感,那RDB方式要比AOF方式更加的高效。
雖然RDB有不少優(yōu)點(diǎn),但它的缺點(diǎn)也是不容忽視的。如果你對(duì)數(shù)據(jù)的完整性非常敏感,那么RDB方式就不太適合你,因?yàn)榧词鼓忝?分鐘都持久化一次,當(dāng)redis故障時(shí),仍然會(huì)有近5分鐘的數(shù)據(jù)丟失。所以,redis還提供了另一種持久化方式,那就是AOF。
【聊聊redis持久化 – AOF】
AOF,英文是Append Only File,即只允許追加不允許改寫的文件。
如前面介紹的,AOF方式是將執(zhí)行過的寫指令記錄下來,在數(shù)據(jù)恢復(fù)時(shí)按照從前到后的順序再將指令都執(zhí)行一遍,就這么簡單。
我們通過配置redis.conf中的appendonly yes就可以打開AOF功能。如果有寫操作(如SET等),redis就會(huì)被追加到AOF文件的末尾。
默認(rèn)的AOF持久化策略是每秒鐘fsync一次(fsync是指把緩存中的寫指令記錄到磁盤中),因?yàn)樵谶@種情況下,redis仍然可以保持很好的處理性能,即使redis故障,也只會(huì)丟失最近1秒鐘的數(shù)據(jù)。
如果在追加日志時(shí),恰好遇到磁盤空間滿、inode滿或斷電等情況導(dǎo)致日志寫入不完整,也沒有關(guān)系,redis提供了redis-check-aof工具,可以用來進(jìn)行日志修復(fù)。
因?yàn)椴捎昧俗芳臃绞剑绻蛔鋈魏翁幚淼脑挘珹OF文件會(huì)變得越來越大,為此,redis提供了AOF文件重寫(rewrite)機(jī)制,即當(dāng)AOF文件的大小超過所設(shè)定的閾值時(shí),redis就會(huì)啟動(dòng)AOF文件的內(nèi)容壓縮,只保留可以恢復(fù)數(shù)據(jù)的最小指令集。舉個(gè)例子或許更形象,假如我們調(diào)用了100次INCR指令,在AOF文件中就要存儲(chǔ)100條指令,但這明顯是很低效的,完全可以把這100條指令合并成一條SET指令,這就是重寫機(jī)制的原理。
在進(jìn)行AOF重寫時(shí),仍然是采用先寫臨時(shí)文件,全部完成后再替換的流程,所以斷電、磁盤滿等問題都不會(huì)影響AOF文件的可用性,這點(diǎn)大家可以放心。
AOF方式的另一個(gè)好處,我們通過一個(gè)“場(chǎng)景再現(xiàn)”來說明。某同學(xué)在操作redis時(shí),不小心執(zhí)行了FLUSHALL,導(dǎo)致redis內(nèi)存中的數(shù)據(jù)全部被清空了,這是很悲劇的事情。不過這也不是世界末日,只要redis配置了AOF持久化方式,且AOF文件還沒有被重寫(rewrite),我們就可以用最快的速度暫停redis并編輯AOF文件,將最后一行的FLUSHALL命令刪除,然后重啟redis,就可以恢復(fù)redis的所有數(shù)據(jù)到FLUSHALL之前的狀態(tài)了。是不是很神奇,這就是AOF持久化方式的好處之一。但是如果AOF文件已經(jīng)被重寫了,那就無法通過這種方法來恢復(fù)數(shù)據(jù)了。
雖然優(yōu)點(diǎn)多多,但AOF方式也同樣存在缺陷,比如在同樣數(shù)據(jù)規(guī)模的情況下,AOF文件要比RDB文件的體積大。而且,AOF方式的恢復(fù)速度也要慢于RDB方式。
如果你直接執(zhí)行BGREWRITEAOF命令,那么redis會(huì)生成一個(gè)全新的AOF文件,其中便包括了可以恢復(fù)現(xiàn)有數(shù)據(jù)的最少的命令集。
如果運(yùn)氣比較差,AOF文件出現(xiàn)了被寫壞的情況,也不必過分擔(dān)憂,redis并不會(huì)貿(mào)然加載這個(gè)有問題的AOF文件,而是報(bào)錯(cuò)退出。這時(shí)可以通過以下步驟來修復(fù)出錯(cuò)的文件:
1.備份被寫壞的AOF文件
2.運(yùn)行redis-check-aof –fix進(jìn)行修復(fù)
3.用diff -u來看下兩個(gè)文件的差異,確認(rèn)問題點(diǎn)
4.重啟redis,加載修復(fù)后的AOF文件
【聊聊redis持久化 – AOF重寫】
AOF重寫的內(nèi)部運(yùn)行原理,我們有必要了解一下。
在重寫即將開始之際,redis會(huì)創(chuàng)建(fork)一個(gè)“重寫子進(jìn)程”,這個(gè)子進(jìn)程會(huì)首先讀取現(xiàn)有的AOF文件,并將其包含的指令進(jìn)行分析壓縮并寫入到一個(gè)臨時(shí)文件中。
與此同時(shí),主工作進(jìn)程會(huì)將新接收到的寫指令一邊累積到內(nèi)存緩沖區(qū)中,一邊繼續(xù)寫入到原有的AOF文件中,這樣做是保證原有的AOF文件的可用性,避免在重寫過程中出現(xiàn)意外。
當(dāng)“重寫子進(jìn)程”完成重寫工作后,它會(huì)給父進(jìn)程發(fā)一個(gè)信號(hào),父進(jìn)程收到信號(hào)后就會(huì)將內(nèi)存中緩存的寫指令追加到新AOF文件中。
當(dāng)追加結(jié)束后,redis就會(huì)用新AOF文件來代替舊AOF文件,之后再有新的寫指令,就都會(huì)追加到新的AOF文件中了。
【聊聊redis持久化 – 如何選擇RDB和AOF】
對(duì)于我們應(yīng)該選擇RDB還是AOF,官方的建議是兩個(gè)同時(shí)使用。這樣可以提供更可靠的持久化方案。