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