一文了解Redis的持久化
我們都知道在對(duì)于Redis的開發(fā)或者面試的過程中,很容易就會(huì)遇到這個(gè)關(guān)于 Redis 持久化的問題,而我們在面試的時(shí)候,經(jīng)常會(huì)有小伙伴只能說出這個(gè) Redis 持久化的兩種方式,后續(xù)可能還會(huì)對(duì)比一些區(qū)別,但是對(duì)于怎么實(shí)現(xiàn)這個(gè)持久化的操作,都不是很熟,而且也并沒有實(shí)際應(yīng)用過,以及什么時(shí)候應(yīng)該使用什么類型的持久化,今天了不起就來給大家說說這個(gè)持久化。
Redis持久化
什么是 Redis 的持久化,我們都知道,Redis 是基于內(nèi)存存儲(chǔ)的 key-value 的數(shù)據(jù)庫,那么如果出現(xiàn)斷電了,這就會(huì)導(dǎo)致數(shù)據(jù)丟失,那么持久化就非常重要了,也就是說,可以把數(shù)據(jù)寫入到硬盤上,而這個(gè)寫入到硬盤上面的操作,就是持久化。
Redis 持久化的兩種方式
- RDB(Redis DataBase)
- AOF(Append Of File)
什么是 RDB 呢?
簡而言之,就是在指定的時(shí)間間隔內(nèi),定時(shí)的將 redis 存儲(chǔ)的數(shù)據(jù)生成Snapshot快照并存儲(chǔ)到磁盤等介質(zhì)上。
那么什么是 AOF 呢?
AOF 則是將 redis 執(zhí)行過的所有寫指令記錄下來,在下次 redis 重新啟動(dòng)時(shí),只要把這些寫指令從前到后再重復(fù)執(zhí)行一遍,就可以實(shí)現(xiàn)數(shù)據(jù)恢復(fù)了。
而 Redis 也是有自己默認(rèn)的持久化的方式的,那就是 RDB 。
RDB持久化方式的原理
我們先說實(shí)現(xiàn)原理:
Redis 使用操作系統(tǒng)的多進(jìn)程 COW(Copy On Write) 機(jī)制來實(shí)現(xiàn)快照持久化,這個(gè)機(jī)制很有意思,也很少人知道。多進(jìn)程 COW 也是鑒定程序員知識(shí)廣度的一個(gè)重要指標(biāo)。
Redis 在持久化時(shí)會(huì)調(diào)用 glibc 的函數(shù) fork 產(chǎn)生一個(gè)子進(jìn)程,快照持久化完全交給子進(jìn)程來處理,父進(jìn)程繼續(xù)處理客戶端請求。子進(jìn)程剛剛產(chǎn)生時(shí),它和父進(jìn)程共享內(nèi)存里面的代碼段和數(shù)據(jù)段。這時(shí)你可以將父子進(jìn)程想像成一個(gè)連體嬰兒,共享身體。這是 Linux 操作系統(tǒng)的機(jī)制,為了節(jié)約內(nèi)存資源,所以盡可能讓它們共享起來。在進(jìn)程分離的一瞬間,內(nèi)存的增長幾乎沒有明顯變化。
子進(jìn)程做數(shù)據(jù)持久化,它不會(huì)修改現(xiàn)有的內(nèi)存數(shù)據(jù)結(jié)構(gòu),它只是對(duì)數(shù)據(jù)結(jié)構(gòu)進(jìn)行遍歷讀取,然后序列化寫到磁盤中。但是父進(jìn)程不一樣,它必須持續(xù)服務(wù)客戶端請求,然后對(duì)內(nèi)存數(shù)據(jù)結(jié)構(gòu)進(jìn)行不間斷的修改。
這個(gè)時(shí)候就會(huì)使用操作系統(tǒng)的 COW 機(jī)制來進(jìn)行數(shù)據(jù)段頁面的分離。數(shù)據(jù)段是由很多操作系統(tǒng)的頁面組合而成,當(dāng)父進(jìn)程對(duì)其中一個(gè)頁面的數(shù)據(jù)進(jìn)行修改時(shí),會(huì)將被共享的頁面復(fù)制一份分離出來,然后對(duì)這個(gè)復(fù)制的頁面進(jìn)行修改。這時(shí)子進(jìn)程相應(yīng)的頁面是沒有變化的,還是進(jìn)程產(chǎn)生時(shí)那一瞬間的數(shù)據(jù)。
而這,就是 fork,也就是多進(jìn)程。
那么我們應(yīng)該怎么去配置,然后怎么知道這個(gè) 默認(rèn)的持久化方式呢?
RDB 修改持久化
在redis.conf中,可以修改rdb備份文件的名稱,默認(rèn)為dump.rdb,如下:
圖片
圖片
而存放目錄也是默認(rèn)為Redis啟動(dòng)命令所在的目錄
從這里我們能去配置 Redis 的持久化的方式。
接下來我們就得看看怎么能觸發(fā)這個(gè)持久化的規(guī)則了。
觸發(fā) RDB 持久化操作
圖片
配置文件我們能看看到。
900秒(15分鐘)后,如果至少有一個(gè)按鍵發(fā)生變化。
300秒(5分鐘)后,如果至少有10個(gè)按鍵發(fā)生變化
60秒后,如果至少有10000個(gè)密鑰發(fā)生更改
而這個(gè) save 就是用來配置備份的規(guī)則的。
其實(shí)這個(gè)就是相當(dāng)于是自動(dòng)備份了,這個(gè)配置直接都是使用的默認(rèn),或者咱們自己去修改這個(gè) save 的操作。
如果我們想要恢復(fù)備份其實(shí)很簡單,其實(shí)當(dāng)你重啟的時(shí)候,他默認(rèn)會(huì)從咱們剛才看到的 dir 下去恢復(fù),所以,如果你修改了備份的目錄,那么你想恢復(fù)備份,那么你就得之前的 dump.rdb 放到 dir 的下面,然后重啟 redis 就可以恢復(fù)了。
既然我們了解了這個(gè) RDB 持久化了,那么接下來就得來說說這個(gè) AOF 持久化了。
AOF 持久化
AOF 日志存儲(chǔ)的是 Redis 服務(wù)器的順序指令序列,AOF 日志只記錄對(duì)內(nèi)存進(jìn)行修改的指令記錄。
假設(shè) AOF 日志記錄了自 Redis 實(shí)例創(chuàng)建以來所有的修改性指令序列,那么就可以通過對(duì)一個(gè)空的 Redis 實(shí)例順序執(zhí)行所有的指令,也就是「重放」,來恢復(fù) Redis 當(dāng)前實(shí)例的內(nèi)存數(shù)據(jù)結(jié)構(gòu)的狀態(tài)。
所以按照使用來說,更多的人會(huì)選擇 RDB 的持久化。
寫入操作
Redis 在收到客戶端修改命令后,先進(jìn)行相應(yīng)的校驗(yàn),如果沒問題,就立即將該命令存追加到 .aof 文件中,也就是先存到磁盤中,然后服務(wù)器再執(zhí)行命令。這樣就算遇到了突發(fā)的宕機(jī)情況情況,也只需將存儲(chǔ)到 .aof 文件中的命令,進(jìn)行一次“命令重演”就可以恢復(fù)到宕機(jī)前的狀態(tài)。
也就是說,他是先存磁盤,然后再去執(zhí)行命令。
而 Redis 為了提升寫入效率,它不會(huì)將內(nèi)容直接寫入到磁盤中,而是將其放到一個(gè)內(nèi)存緩存區(qū)(buffer)中等到緩存區(qū)被填滿時(shí)采用異步真正將緩存區(qū)中的內(nèi)容寫入到磁盤里。
所以就有了問題,如果機(jī)器突然宕機(jī),AOF 日志內(nèi)容可能還沒有來得及完全刷到磁盤中,這個(gè)時(shí)候就會(huì)出現(xiàn)日志丟失。
我們都能知道這么淺顯的問題,那么 Redis 一定是可以解決的,解決方案都很粗暴,直接就是配置文件上寫明了。
圖片
- Everysec默認(rèn)
服務(wù)器每一秒調(diào)用一次 fsync 函數(shù),將緩沖區(qū)里面的命令寫入到硬盤。這種模式下,服務(wù)器出現(xiàn)故障,最多只丟失一秒鐘內(nèi)的執(zhí)行的命令數(shù)據(jù),通常都使用它作為 AOF 配置策略
- Always
服務(wù)器每寫入一個(gè)命令,就調(diào)用一次 fsync函數(shù),將緩沖區(qū)里面的命令寫入到硬盤。這種模式下,服務(wù)器出現(xiàn)故障,也不會(huì)丟失任何已經(jīng)成功執(zhí)行的命令數(shù)據(jù),但是其執(zhí)行速度較慢
- No
服務(wù)器不主動(dòng)調(diào)用 fsync 函數(shù),由操作系統(tǒng)決定何時(shí)將緩沖區(qū)里面的命令寫入到硬盤。這種模式下,服務(wù)器遭遇意外停機(jī)時(shí),丟失命令的數(shù)量是不確定的,所以這種策略,不確定性較大,不安全。
而我們?nèi)绻x用了 AOF ,那么在生產(chǎn)環(huán)境的服務(wù)器中,Redis 通常是每隔 1s 左右執(zhí)行一次 fsync 操作( Everysec),這樣既保持了高性能,也讓數(shù)據(jù)盡可能的少丟失。
AOF 配置開啟
AOF默認(rèn)不開啟,可以在 redis.conf 文件中對(duì)AOF進(jìn)行配置開啟:
appendonly no # 是否開啟AOF,yes:開啟,no:不開啟,默認(rèn)為no
appendfilename "appendonly.aof" # aof文件名稱,默認(rèn)為appendonly.aof
dir ./ # aof文件所在目錄,默認(rèn)./,表示執(zhí)行啟動(dòng)命令時(shí)所在的目錄
AOF 的備份恢復(fù)
AOF的備份機(jī)制和性能雖然和RDB不同,但是備份和恢復(fù)的操作同RDB一樣,都是拷貝備份文件,需要恢復(fù)時(shí)再拷貝到Redis工作目錄下,啟動(dòng)系統(tǒng)即加載。
所以關(guān)于 Redis 的持久化操作,你學(xué)會(huì)了么?