前邊我們已經介紹了Redis五種資料型別的命令與組態檔的基本配置,今天讓我們從理論和配置兩個層面來揭開Redis持久化的神秘面紗,
所謂持久化可以簡單理解為將記憶體中的資料保存到硬碟上存盤的程序,持久化之后的資料在系統重啟或者宕機之后依然可以進行訪問,保證了資料的安全性,
Redis有兩種持久化方案,一種是快照方式(SNAPSHOTTING),簡稱RDB;一種是只追加模式(APPEND ONLY MODE),稱為AOF,接下來讓我們分別了解一下它們的使用與注意事項,
RDB
RDB為Redis DataBase的縮寫,是 Redis 默認的持久化方案,它能夠在指定的時間間隔內將記憶體資料集快照(snapshot)寫入磁盤,恢復時將快照檔案( dump.rdb )讀回記憶體,

我們先來扒一下組態檔中的SNAPSHOTTING:
組態檔
save <seconds> <changes>
在給定的秒數內,如果對資料庫執行的寫入運算元達到設定的值,則將資料同步到資料檔案,支持多個條件配合,Redis默認組態檔中提供了三個條件:
save 900 1 //900s內有1個更改
save 300 10 //300s內有10個更改
save 60 10000 //60s內有10000次更改
注意:若不想用RDB方案,可以把 save "" 的注釋打開,上邊三個注釋掉,
stop-writes-on-bgsave-error yes
當bgsave出現錯誤時,Redis是否停止執行寫命令;
- 如果為
yes,則當硬碟出現問題時,Redis將停止接受寫入操作,這樣我們可以及時發現,避免資料的大量丟失; - 如果為
no,則Redis無視bgsave的錯誤繼續執行寫命令,
如果已經設定了對
Redis服務器的正確監視和持久性,即采用了其他手段發現和控制資料完整性,可能希望禁用此功能,以便即使在磁盤、權限等方面出現問題時,Redis仍能正常作業,
注意:如果后臺保存程序將再次開始作業,Redis將自動允許再次寫入,
rdbcompression yes
指定存盤到本地資料庫時是否壓縮(Redis采用LZF壓縮)資料,默認為yes,如果為了節省CPU時間,可以關閉該選項,但會導致資料庫檔案變得巨大,
rdbchecksum yes
從RDB版本5開始,在存盤快照后,還可以使用CRC64演算法來進行資料校驗,CRC64校驗放在檔案的末尾,開啟之后,保存和加載RDB檔案時會增加大約10%的性能消耗,如果希望獲取到最大的性能提升,可以關閉此功能,
禁用校驗和創建的RDB檔案的校驗和為零,這將告訴加載代碼跳過檢查,
dbfilename dump.rdb
指定本地資料庫檔案名,重啟之后自動加載進記憶體,手動執行save 命令的話即刻生效,
大坑請注意:
flushall、shutdown命令都會清空并提交至dump.rdb
dir ./
指定本地資料庫存放目錄,
理論
作業方式
- 當
Redis需要保存dump.rdb檔案時,它會呼叫系統函式fork(),創建一個子行程(與主行程完全一致); - 子行程將資料集寫入臨時檔案
RDB中; - 當子行程完成對新
RDB檔案的寫入時,Redis用新RDB檔案替換原來的RDB檔案,并洗掉舊的RDB檔案,
這種作業方式使得 Redis 可以從寫時復制(copy-on-write)機制中獲益,
如何觸發RDB快照
- 組態檔中默認的快照配置;
- 命令
save(阻塞, 只管保存快照,其他的等待)或者是bgsave(異步)命令,快照同時還可以回應客戶端命令; - 執行
flushall命令,清空資料庫所有資料,意義不大; - 執行
shutdown命令,保證服務器正常關閉且不丟失任何資料,意義也不大,
通過RDB檔案恢復資料
在實際開發中,一般會考慮到物理機硬碟損壞的情況,所以我們會選擇備份dump.rdb檔案,將備份的dump.rdb 檔案拷貝到redis的安裝目錄的bin目錄下,重啟redis服務即可,
優點
RDB是一個非常緊湊的檔案,非常適用于資料集的備份;RDB是一個緊湊的單一檔案,很方便傳送到另一個遠端資料中心或者亞馬遜的S3(可能加密),非常適用于災難恢復;Redis的主行程不進行I/O操作,確保了極高的性能;- 適合大規模資料的恢復,對于資料的完整性和一致性要求不高的話,
RDB比AOF方式更加高效,
缺點
- 在
Redis意外宕機時,你可能會丟失幾分鐘的資料; RDB需要經常fork子行程來保存資料集到硬碟上,當資料集比較大的時候,fork的程序是非常耗時的,可能會導致Redis在一些毫秒級內不能回應客戶端的請求,如果資料集巨大并且CPU性能不是很好的情況下,這種情況會持續1秒;AOF也需要fork,但是可以調節重寫日志檔案的頻率來提高資料集的耐久度,
AOF
為了解決RDB方式在宕機時丟失資料過多的問題,從1.1 版本開始,Redis增加了一種durable的持久化方式:AOF,
AOF是Append Only File的縮寫,默認不開啟,AOF以日志的形式來記錄每個寫操作,只允許追加檔案但不可以改寫檔案,當服務器重啟的時候會重新執行這些命令來恢復原始的資料,
我們再來看一下組態檔中的APPEND ONLY MODE:
組態檔
appendonly no
默認為關閉狀態,改為yes打開持久化,AOF和RDB可以同時啟用而不會出現問題,
appendfilename "appendonly.aof"
檔案默認名稱,啟動即創建,加載先于dump.rdb檔案
appendfsync
同步策略:系統函式fsync() 告訴作業系統在磁盤上實際寫入資料,Redis支持三種不同的模式
appendfsync always //每次發生資料變更會被立即記錄到磁盤,性能較差但資料完整性比較好
appendfsync everysec //默認推薦,異步操作,每秒記錄,如果宕機,有1秒內資料丟失
appendfsync no //不同步,只有在作業系統需要時在重繪資料
要想了解接下來的配置內容,先得說一下“日志重寫”的原理:
重寫
由于AOF采用的是將命令追加到檔案末尾的方式,所以隨著寫入命令的不斷增加,AOF檔案的體積會變得越來越大,為避免出現此種情況,新增了重寫機制:可以在不打斷服務客戶端的情況下,對AOF檔案進行重建(rebuild),
重寫觸發: 通過執行bgrewriteaof命令,可以生成一個新的AOF檔案,該檔案包含重建當前資料集所需的最少命令,Redis 2.2需手動執行該命令,Redis 2.4則可以通過修改組態檔的方式自動觸發(配置在下邊涉及),
重寫原理:
Redis執行系統函式fork(),創建一個子行程(與主行程完全一致);- 子行程開始將新
AOF檔案的內容寫入到臨時檔案; - 對于所有新執行的寫入命令,父行程一邊將它們累積到一個記憶體快取中,一邊將這些改動追加到現有
AOF檔案的末尾,這樣即使在重寫的中途發生停機,現有的AOF檔案也是安全的; - 當子行程完成重寫作業時,它給父行程發送一個信號,父行程在接收到信號之后,將記憶體快取中的所有資料追加到新
AOF檔案的末尾, Redis原子地用新檔案替換舊檔案,之后所有命令都會直接追加到新AOF檔案的末尾,
no-appendfsync-on-rewrite no
當我們同時執行主行程的寫操作和子行程的重寫操作時,兩者都會操作磁盤,而重寫往往會涉及到大量的磁盤操作,這樣就會造成主行程在寫aof檔案的時候出現阻塞的情形,
為了解決這個問題,no-appendfsync-on-rewrite引數出場了,
- 如果該引數設定為
no,是最安全的方式,不會丟失資料,但是要忍受阻塞的問題; - 如果設定為
yes,這就相當于將appendfsync設定為no,這說明并沒有執行磁盤操作,只是寫入了緩沖區,因此這樣并不會造成阻塞(因為沒有競爭磁盤),但是如果這個時候redis掛掉,就會丟失資料,丟失多少資料呢?在linux的作業系統的默認設定下,最多會丟失30s的資料,
因此,如果應用系統無法忍受延遲,而可以容忍少量的資料丟失,則設定為yes;如果應用系統無法忍受資料丟失,則設定為no,
auto-aof-rewrite-percentage 100
重寫百分比,默認為上次重寫后aof檔案大小的一倍,
auto-aof-rewrite-min-size 64mb
重寫觸發的最小值:64mb,
根據auto-aof-rewrite-min-size和auto-aof-rewrite-percentage引數確定自動觸發時機,Redis會記錄上次重寫時的AOF大小,默認配置是當AOF檔案大小是上次rewrite后大小的一倍且檔案大于64M時觸發,
大型互聯網公司一般都是
3G起步
aof-load-truncated yes
當AOF檔案被截斷時,即AOF檔案的最后命令不完整,如果此時啟動Redis,會將AOF資料加載回記憶體,此時便會出現問題,
- yes:加載一個截斷的
AOF,Redis服務器開始發出日志,通知用戶該事件; - no:服務器將中止并出現錯誤,拒絕啟動,
當我們得知AOF檔案報錯時,可以用以下方法來修復出錯的 AOF 檔案:
-
為現有的
AOF檔案創建一個備份; -
使用
Redis附帶的redis-check-aof命令,對原來的AOF檔案進行修復;-
redis-check-aof –fix -
redis-check-aof --fix appendonly.aof修復命令,殺光不符合規范的語法
-
-
(可選)使用
diff -u對比修復后的AOF檔案和原始AOF檔案的備份,查看兩個檔案之間的不同之處; -
重啟
Redis服務器,等待服務器載入修復后的AOF檔案,并進行資料恢復,
aof-use-rdb-preamble yes
在重寫AOF檔案時,Redis能夠在AOF檔案中使用RDB前導,以加快重寫和恢復速度,啟用此選項后,重寫的AOF檔案由兩個不同的節組成:RDB file、AOF tail
加載Redis時,會識別AOF檔案以Redis字串開頭,并加載帶前綴的RDB檔案,然后繼續加載AOF尾部,
理論
優點
- 資料的完整性和一致性更高,
AOF的持久化通過使用不同的策略,最多丟失1秒的資料; AOF檔案是一個只進行追加的日志檔案,不需要寫入seek;Redis可以在AOF檔案體積變得過大時,自動地在后臺對AOF進行重寫,重寫操作是絕對安全的;AOF檔案記錄的寫入操作以Redis協議的格式保存,容易讀懂,容易對檔案進行分析;
缺點
- 對于相同的資料集來說,
AOF檔案的體積通常要大于RDB檔案的體積; - 根據所使用的
fsync策略,AOF的速度可能會慢于RDB,
在一般情況下,每秒
fsync的性能依然非常高,而關閉fsync可以讓AOF的速度和RDB一樣快, 即使在高負荷之下也是如此, 不過在處理巨大的寫入載入時,RDB可以提供更有保證的最大延遲時間(latency),
對比與總結
如何選擇使用哪種持久化方式?
一般來說,如果想達到足以媲美 PostgreSQL 的資料安全性,應該同時使用兩種持久化功能,
如果非常關心資料,但仍然可以承受數分鐘以內的資料丟失,那么可以只使用 RDB 持久化,
由于AOF持久化的實時性更好,即當行程意外退出時丟失的資料更少,因此AOF是目前主流的持久化方式,
有很多用戶都只使用AOF持久化,但我們并不推薦這種方式:因為定時生成 RDB 快照(snapshot)非常便于進行資料庫備份,并且 RDB 恢復資料集的速度也要比 AOF 恢復的速度要快,
AOF和RDB之間的相互作用
在版本號大于等于 2.4 的 Redis 中,BGSAVE 執行的程序中,不可以執行 BGREWRITEAOF ,反過來說,在 BGREWRITEAOF 執行的程序中,也不可以執行 BGSAVE,這可以防止兩個 Redis 后臺行程同時對磁盤進行大量的 I/O 操作,
如果 BGSAVE 正在執行,并且用戶顯示地呼叫 BGREWRITEAOF 命令,那么服務器將向用戶回復一個 OK 狀態, 并告知用戶BGREWRITEAOF 已經被預定執行:一旦 BGSAVE 執行完畢,BGREWRITEAOF 就會正式開始,
當 Redis 啟動時,如果 RDB持久化和 AOF 持久化都被打開了, 那么程式會優先使用 AOF 檔案來恢復資料集,因為 AOF 檔案所保存的資料通常是最完整的,
備份redis資料
- 創建一個定期任務(
cron job),每小時將一個RDB檔案備份到一個檔案夾,并且每天將一個RDB檔案備份到另一個檔案夾; - 確保快照的備份都帶有相應的日期和時間資訊,每次執行定期任務腳本時,使用
find命令來洗掉過期的快照; - 至少每天一次,將
RDB備份到你的資料中心之外,或者至少是備份到你運行Redis服務器的物理機器之外,
性能建議
在實際應用時,因為RDB檔案只用作后備用途,建議只在slave上持久化RDB檔案,而且只需要15分鐘備份一次就夠了,只保留save 900 1這條規則,
如果開啟AOF,好處是在最惡劣情況下也只會丟失不超過2秒資料,啟動腳本較簡單只load自己的AOF檔案就可以了,代價一是帶來了持續的IO,二是AOF rewrite 的最后將rewrite程序中產生的新資料寫到新檔案造成的阻塞幾乎是不可避免的,
只要硬碟許可,應該盡量減少AOF rewrite的頻率,AOF重寫的基礎大小默認值64M太小了,可以設定到5G以上,默認超過原大小的100%時重寫可以改到適當的數值,
如果不開啟AOF,僅靠Master-Slave Replication實作高可用性也可以,能省掉一大筆IO,也減少了rewrite時帶來的系統波動,代價是如果Master/Slave 同時倒掉,會丟失十幾分鐘的資料,啟動腳本也要比較兩個Master/Slave中的RDB檔案,載入較新的那個,
以上就是今天的全部內容了,如果你有不同的意見或者更好的idea,歡迎聯系阿Q,添加阿Q可以加入技術交流群參與討論呦!
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/296712.html
標籤:Java
下一篇:面試官問我MySQL索引,我
