? ? ? ? 在上一篇文章中對Redis的兩種持久化方式進行了介紹,還介紹了各自的優缺點以及如何選擇,這篇文章就介紹一下redis的持久化應該怎么配置,數據恢復應該怎么操作。
1.RDB配置和數據恢復流程
(1).RDB的配置
????????首先找到redis的配置文件,我的redis裝在了centos上,配置文件的目錄為:/etc/redis/6379.conf,打開它找到snapshotting。
????????可以在snapshotting下配置多個save,這個save其實就是檢查點,redis可以配置多個檢查點,每到一個檢查點,就會去check一下,是否有指定的key數量發生了變更,如果有,就生成一個新的dump.rdb文件。當然,我們也可以通過手動調用save或者bgsave命令,同步或異步執行rdb快照生成。
save 900 1:表示每隔900秒如果有1個key發生變化就會生成一個新的rdb文件
save 300 10:表示每隔300秒如果有10個key發生變化就會生成一個新的rdb文件
save 60 10000:表示每隔60秒如果有10000個key發生變化就會生成一個新的rdb文件
? ? ? ? save 5 1 是我們為了實驗方便設置的一個檢查點
(2).RDB持久化機制的工作流程
(a).redis根據配置自己嘗試去生成rdb快照文件
(b).fork一個子進程出來
(c).子進程嘗試將數據dump到臨時的rdb快照文件中
(d).完成rdb快照文件的生成之后,就替換之前的舊的快照文件
同時只有一個dump.rdb,每次生成一個新的快照,都會覆蓋之前的老快照。
(3).rdb數據恢復實驗
????????首先我們打開redis-cli存儲一些數據(ps:此時我們還沒有在redis.conf中添加save 5 1):
????????現在我們把一些數據都已經放在了redis里面,然后我們shut down redis,并且重啟redis:
????????那么現在就有點奇怪了,我們還沒有添加檢查點 save 5 1,為什么數據還是在redis中?其實在我們shutdown redis-cli的時候就已經自動生成了一次快照文件了,所以上述操作是安全操作!(那你說個屁!);
????????好的,我們接下來就不shutdown 而是直接kill -9 來粗暴殺死redis的進程并且刪除掉/var/run 下面redis_6379.pid,模擬redis的故障場景:
????????這時就發現我們剛剛添加的三個值都拿不到了。
????????然后我們自己手動設置一個檢查點:save 5 1到redis的配置文件中。然后再次將剛剛三個值保存到redis中,然后等待五秒,重復上面殺死redis進程的操作,然后在重啟redis,現在我們就發現之前的值沒有因為redis被殺死而丟失。
????????好的,以上就是我們使用RDB進行數據恢復的實驗,save 5 1這個檢查點記得注釋掉或者刪除,我們沒有必要這么頻繁的去生成快照。
2.AOF配置和數據恢復流程
(1).AOF的配置
????????我們在redis的配置文件中搜索appendonly就可以找到aof的相關配置了。
????????其實redis默認的持久化方式時rdb,rdb是默認打開的,我們要使用aof的話就需要單獨打開。
????????在生產中,aof一般都是要打開的,除非你覺得丟失幾分鐘的數據無大礙。
????????設置 appendonly yes 后就打開了aof,打開aof之后,redis每接受到一條命令都會先寫入到日志文件中,當然不會直接寫到aof文件中,他會先寫入到ox cache中,然后每隔一段時間調用操作系統的fsync操作,將os cache中的數據同步到磁盤上的aof文件中。
????????而且,當rdb和aof同時開啟的時候,redis也會優先aof來進行數據恢復,因為aof的數據相對來說比rdb完整。
aof有三種策略供君選擇:
appendfsync always:?
????????每次寫入一條數據,立即將這個數據對應的寫日志fsync到磁盤上去,性能非常非常差,吞吐量很低; 如果說你要求redis里的數據一條都不丟,那就選擇此策略。
appendfsync everysec:
????????每秒將os cache中的數據fsync到磁盤,這個最常用的,生產環境一般都這么配置,性能很高,QPS還是可以上萬的。
appendfsync no:
? ? ? ?redis?僅僅負責將數據寫入os cache就不管了,然后os自己會時不時根據自己的策略將數據刷入磁盤,人為不可控。
(2).aof數據恢復實驗
????????首先我們打開aof的開關,啟用aof,然后向redis中添加數據,然后找到aof文件(我的持久化文件放在:/var/redis/6379),aof中按順序存放指令,如果你知道aof的規則的話是可以讀懂的,也就是說,aof文件是可讀的。
????????我使用的策略是everysec,也就是每秒調用一次fsync,redis先將數據寫入os cache中,一秒后才調用fsync操作將數據寫入磁盤中,數據沒有寫入磁盤的話是不安全的,也就是說,everysec還是有可能丟失一秒的數據。
????????我們將redis的進程殺死,看看數據恢復成功了沒:
? ? ? ? 數據成功的被恢復了,redis進程啟動的時候,直接就會從appendonly.aof中加載所有的日志,把內存中的數據恢復回來。
(3).aof的rewrite機制
redis中的數據其實有限的,很多數據可能會自動過期,可能會被用戶刪除,可能會被redis用緩存清除的算法清理掉。redis中的數據會不斷淘汰掉舊的,就一部分常用的數據會被自動保留在redis內存中。所以可能很多之前的已經被清理掉的數據,對應的寫日志還停留在AOF中,AOF日志文件就一個,會不斷的膨脹,變得很大很大。所以AOF會自動在后臺每隔一定時間做rewrite操作,比如日志里已經存放了針對100w數據的寫日志了; redis內存只剩下10萬; 基于內存中當前的10萬數據構建一套最新的日志,到AOF中; 覆蓋之前的老日志; 確保AOF日志文件不會過大,保持跟redis內存數據量一致。
首先,我們先去配置文件中搜索一下rewrite,可以看看相關的說明。
????????rewrite的策略我們使用默認的就好,有興趣的讀者可以去研究一下redis的rewrite策略,我在這里就講一下上圖對應的兩個參數,這兩個參數相對來說比較重要。這兩個參數怎么解釋呢?比如說上一次AOF rewrite之后,是128mb。然后就會接著128mb繼續寫AOF的日志,如果發現增長的比例,超過了之前的100%,256mb,就可能會去觸發一次rewrite但是此時還要去跟min-size,64mb去比較,256mb > 64mb,才會去觸發rewrite。
(4).aof rewrite過程詳解
(a).redis fork一個子進程
(b).子進程基于當前內存中的數據,構建日志,開始往一個新的臨時的AOF文件中寫入日志
(c).redis主進程,接收到client新的寫操作之后,在內存中寫入日志,同時新的日志也繼續寫入舊的AOF文件
(d).子進程寫完新的日志文件之后,redis主進程將內存中的新日志再次追加到新的AOF文件中
(e).用新的日志文件替換掉舊的日志文件
(5).aof文件破損修復
????????當redis在append數據到aof文件中的時候,服務器宕機了,那么就可能造成aof文件的損壞,redis提供了相關的工具來修復破損的aof文件。使用redis-check-aof --fix命令來修復破損的AOF文件。
????????我們來做一個小實驗,我們把備份的aof文件copy出來一份,然后更改它,是他破損,然后使用redis的修復工具來修復它。
? ? ? ? 首先將aof文件copy出來
我們編輯這個文件,然后更改這個文件:
然后使用redis的修復工具修復這個文件:
redis修復工具就會把最后那行多余的指令刪除掉。
3.RDB和AOF同時工作
? ? ? ? 因為redis的持久化操作是非常消耗性能的,那么當他們倆發生沖突的時候會怎么辦?
(1)如果RDB在執行snapshotting操作,那么redis不會執行AOF rewrite; 如果redis再執行AOF rewrite,那么就不會執行RDB snapshotting
(2)如果RDB在執行snapshotting,此時用戶執行BGREWRITEAOF命令,那么等RDB快照生成之后,才會去執行AOF rewrite
(3)同時有RDB snapshot文件和AOF日志文件,那么redis重啟的時候,會優先使用AOF進行數據恢復,因為其中的日志更完整
(4)在有rdb的dump和aof的appendonly的同時,rdb里也有部分數據,aof里也有部分數據,這個時候其實會發現,rdb的數據不會恢復到內存中
大家也可做個小實驗,將aof中的數據刪除一條(這條數據已經持久化到rdb中),然后用redis的修復工具進行修復,在用這個文件替換aof文件,重啟redis,最后會發現rdb中的數據不會被恢復到內存中。
redis的數據恢復完全是依賴于底層的磁盤的持久化的,如果rdb和aof上都沒有數據,那就真的沒了。
4.在實際項目的使用中,我們應該如何配置和使用呢?
(1).配置策略
????????在企業級的項目中,我們使用rdb的默認配置也無大礙,即:
save 900 1
save 300 10
save 60 10000
????????唯一可能要調整的就是 save 60 10000 這個檢查點,因為rdb的生成還是比較耗費資源的,如果說低峰期數據量很小,那么也沒太大必要。但是如果你要保證RDB最多丟一分鐘的數據,那么剩下的就是你自己根據實際情況去配置,到底是一分鐘-10000生成rdb,還是說設置成1分鐘-1000生成rdb。
????aof的話這里推薦把他打開,調用fsync的策略推薦使用everysec,然后根據你項目的實際情況去設置以下兩個屬性:
auto-aof-rewrite-percentage 100 這個屬性改的必要也不是特別的大
auto-aof-rewrite-min-size 64mb 這個根據你的數據量來定
(2).數據備份方案
RDB的話是非常適合做冷備的,每次RDB生成完成之后就不會再修改了,備份的方案可以這樣:
(a).寫crontab定時調度腳本去做數據備份
(b).每小時都copy一份rdb的備份,到一個目錄中去,僅僅保留最近48小時的備份
(c).每天都保留一份當日的rdb的備份,到一個目錄中去,僅僅保留最近1個月的備份
(d).每次copy備份的時候,都把太舊的備份給刪了
(e).每天晚上將當前服務器上所有的數據備份,發送一份到遠程的云服務上去
每小時copy一次備份,刪除48小時前的數據
crontab -e
0 * * * * sh /usr/local/redis/copy/redis_rdb_copy_hourly.sh
redis_rdb_copy_hourly.sh
```
#!/bin/sh
cur_date=`date +%Y%m%d%k`
rm -rf /usr/local/redis/snapshotting/$cur_date
mkdir /usr/local/redis/snapshotting/$cur_date
cp /var/redis/6379/dump.rdb /usr/local/redis/snapshotting/$cur_date
del_date=`date -d -48hour +%Y%m%d%k`
rm -rf /usr/local/redis/snapshotting/$del_date
```
每天copy一次備份
crontab -e
0 0 * * * sh /usr/local/redis/copy/redis_rdb_copy_daily.sh
redis_rdb_copy_daily.sh
```
#!/bin/sh
cur_date=`date +%Y%m%d`
rm -rf /usr/local/redis/snapshotting/$cur_date
mkdir /usr/local/redis/snapshotting/$cur_date
cp /var/redis/6379/dump.rdb /usr/local/redis/snapshotting/$cur_date
del_date=`date -d -1month +%Y%m%d`
rm -rf /usr/local/redis/snapshotting/$del_date
```
每天一次將所有數據上傳一次到遠程的云服務器上去
(3).數據恢復方案
(a).如果是redis進程掛掉,那么重啟redis進程即可,直接基于AOF日志文件恢復數據。
(b).如果是redis進程所在機器掛掉,那么重啟機器后,嘗試重啟redis進程,嘗試直接基于AOF日志文件進行數據恢復。AOF沒有破損,也是可以直接基于AOF恢復的,如果AOF文件出現了破損,則用redis的修復工具修復之后在進行恢復。
(c).如果redis當前最新的AOF和RDB文件出現了丟失/損壞,那么可以嘗試基于該機器上當前的某個最新的RDB數據副本進行數據恢復。
(d).如果當前機器上的所有RDB文件全部損壞,那么從遠程的云服務上拉取最新的RDB快照回來恢復數據。
(e).如果是發現有重大的數據錯誤,比如某個小時上線的程序一下子將數據全部污染了,數據全錯了,那么可以選擇某個更早的時間點,對數據進行恢復。
(4).基于RDB冷備恢復數據
????????基于rdb冷備其實是有一些小坑的,這里拿出來記錄一下,如果你同時打開RDB和AOF,如果你使用的是AOF的冷備去恢復數據,那么很簡單,將redis的aof文件替換成你的冷備然后重啟redis就行了。
????????但是要是你使用的是RDB的冷備,你首先要把redis現有的aof文件刪掉,然后把rdb文件替換成你的冷備,但是由于你開著aof,所以在aof啟動的時候會直接生成一份空的aof文件,而你的RDB冷備會被無視掉,過了一段時間可能會被重寫掉。你可能會想,那我們把AOF關掉不就行了嗎?我們把AOF關掉,重啟redis,確實,RDB的數據會被恢復到redis中,現在數據回來了,但是AOF不能關掉,所以你再次修改配置文件打開AOF重啟redis,這時你發現辛辛苦苦恢復的數據又沒了,其實還是因為打開AOF重新生成了一份空的AOF文件,RDB里面就算有數據也不會恢復到redis當中。那么怎么解決呢?我們可以通過熱修改redis屬性的方式進行恢復,我們先把redis的AOF關掉,用RDB冷備恢復數據,在redis-cli 中使用 config set 指令來開啟AOF,等RDB冷備的數據全被寫入AOF后,再修改配置文件打開AOF,重啟redis即可。以下是具體的流程:
(a).停止redis
(b).關閉aof
(c).拷貝rdb備份
(d).重啟redis,確認數據恢復
(e).直接在命令行熱修改redis配置,打開aof,redis就會將內存中的數據對應的日志,寫入aof文件中
(f).此時aof和rdb兩份數據文件的數據就同步了