前邊我們已經介紹了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可以加入技術交流羣參與討論呦!