一、持久化的作用
1. 什么是持久化
持久化(Persistence),即把數據(如內存中的對象)保存到可永久保存的存儲設備中(如磁盤)。
持久化Redis所有數據保持在內存中,對數據的更新將異步地保存到磁盤上。

2. 持久化的實現方式
快照方式持久化
快照方式持久化就是在某時刻把所有數據進行完整備份。
例:Mysql的Dump方式、Redis的RDB方式。
寫日志方式持久化
寫日志方式持久化就是把用戶執行的所有寫指令(增刪改)備份到文件中,還原數據時只需要把備份的所有指令重新執行一遍即可。
例:Mysql的Binlog、Redis的AOF、Hbase的HLog。
二、RDB
1. 什么是RDB
RDB簡介

RDB持久化方式能夠在指定的時間間隔能對你的數據進行快照存儲。
在默認情況下, Redis 將數據庫快照保存在名字為 dump.rdb的二進制文件中。
在 Redis 運行時, RDB 程序將當前內存中的數據庫快照保存到磁盤文件中, 在 Redis 重啟動時, RDB 程序可以通過載入 RDB 文件來還原數據庫的狀態。
工作方式
當 Redis 需要保存 dump.rdb 文件時, 服務器執行以下操作:
- Redis 調用forks。同時擁有父進程和子進程。
- 子進程將數據集寫入到一個臨時 RDB 文件中。
- 當子進程完成對新 RDB 文件的寫入時,Redis 用新 RDB 文件替換原來的 RDB 文件,並刪除舊的 RDB 文件。
這種工作方式使得 Redis 可以從寫時復制(copy-on-write)機制中獲益。
2. RDB的三種主要觸發機制
save命令(同步數據到磁盤上)
save
命令執行一個同步操作,以RDB文件的方式保存所有數據的快照。
127.0.0.1:6379> save
OK
由於 save
命令是同步命令,會占用Redis的主進程。若Redis數據非常多時,save
命令執行速度會非常慢,阻塞所有客戶端的請求。
因此很少在生產環境直接使用SAVE 命令,可以使用BGSAVE 命令代替。如果在BGSAVE命令的保存數據的子進程發生錯誤的時,用 SAVE命令保存最新的數據是最后的手段。
bgsave命令(異步保存數據到磁盤上)
bgsave
命令執行一個異步操作,以RDB文件的方式保存所有數據的快照。
127.0.0.1:6379> bgsave
Background saving started
Redis使用Linux系統的fock()
生成一個子進程來將DB數據保存到磁盤,主進程繼續提供服務以供客戶端調用。
如果操作成功,可以通過客戶端命令LASTSAVE來檢查操作結果。
save
與 bgsave
對比
命令 | save | bgsave |
---|---|---|
IO類型 | 同步 | 異步 |
阻塞? | 是 | 是(阻塞發生在fock(),通常非常快) |
復雜度 | O(n) | O(n) |
優點 | 不會消耗額外的內存 | 不阻塞客戶端命令 |
缺點 | 阻塞客戶端命令 | 需要fock子進程,消耗內存 |
自動生成RDB
除了手動執行 save
和 bgsave
命令實現RDB持久化以外,Redis還提供了自動自動生成RDB的方式。
你可以通過配置文件對 Redis 進行設置, 讓它在“ N 秒內數據集至少有 M 個改動”這一條件被滿足時, 自動進行數據集保存操作。
比如說, 以下設置會讓 Redis 在滿足“ 60 秒內有至少有 1000 個鍵被改動”這一條件時, 自動進行數據集保存操作:
save 60 1000
3. RDB相關配置
# RDB自動持久化規則
# 當 900 秒內有至少有 1 個鍵被改動時,自動進行數據集保存操作
save 900 1
# 當 300 秒內有至少有 10 個鍵被改動時,自動進行數據集保存操作
save 300 10
# 當 60 秒內有至少有 10000 個鍵被改動時,自動進行數據集保存操作
save 60 10000
# RDB持久化文件名
dbfilename dump-<port>.rdb
# 數據持久化文件存儲目錄
dir /var/lib/redis
# bgsave發生錯誤時是否停止寫入,通常為yes
stop-writes-on-bgsave-error yes
# rdb文件是否使用壓縮格式
rdbcompression yes
# 是否對rdb文件進行校驗和檢驗,通常為yes
rdbchecksum yes
4. RDB的優點
- RDB是一個非常緊湊的文件,它保存了某個時間點得數據集,非常適用於數據集的備份,比如你可以在每個小時報保存一下過去24小時內的數據,同時每天保存過去30天的數據,這樣即使出了問題你也可以根據需求恢復到不同版本的數據集。
- RDB是一個緊湊的單一文件,很方便傳送到另一個遠端數據中心或者亞馬遜的S3(可能加密),非常適用於災難恢復。
- RDB在保存RDB文件時父進程唯一需要做的就是fork出一個子進程,接下來的工作全部由子進程來做,父進程不需要再做其他IO操作,所以RDB持久化方式可以最大化redis的性能。
- 與AOF相比,在恢復大的數據集的時候,RDB方式會更快一些。
5. RDB的缺點
- 耗時、耗性能。RDB 需要經常fork子進程來保存數據集到硬盤上,當數據集比較大的時候,fork的過程是非常耗時的,可能會導致Redis在一些毫秒級內不能響應客戶端的請求。如果數據集巨大並且CPU性能不是很好的情況下,這種情況會持續1秒,AOF也需要fork,但是你可以調節重寫日志文件的頻率來提高數據集的耐久度。
- 不可控、丟失數據。如果你希望在redis意外停止工作(例如電源中斷)的情況下丟失的數據最少的話,那么RDB不適合你。雖然你可以配置不同的save時間點(例如每隔5分鍾並且對數據集有100個寫的操作),是Redis要完整的保存整個數據集是一個比較繁重的工作,你通常會每隔5分鍾或者更久做一次完整的保存,萬一在Redis意外宕機,你可能會丟失幾分鍾的數據。
三、AOF
1. 什么是AOF
快照功能(RDB)並不是非常耐久(durable): 如果 Redis 因為某些原因而造成故障停機, 那么服務器將丟失最近寫入、且仍未保存到快照中的那些數據。 從 1.1 版本開始, Redis 增加了一種完全耐久的持久化方式: AOF 持久化。
你可以在配置文件中打開AOF方式:
appendonly yes
打開AOF后, 每當 Redis 執行一個改變數據集的命令時(比如 SET), 這個命令就會被追加到 AOF 文件的末尾。這樣的話, 當 Redis 重新啟時, 程序就可以通過重新執行 AOF 文件中的命令來達到重建數據集的目的。
AOF運行原理 - 創建
AOF運行原理 - 恢復
2. AOF持久化的三種策略
你可以通過配置文件配置 Redis 多久才將數據 fsync 到磁盤一次。
always
每次有新命令追加到 AOF 文件時就執行一次 fsync :非常慢,也非常安全。
everysec
每秒 fsync 一次:足夠快(和使用 RDB 持久化差不多),並且在故障時只會丟失 1 秒鍾的數據。
推薦(並且也是默認)的措施為每秒 fsync 一次, 這種 fsync 策略可以兼顧速度和安全性。
no
從不 fsync :將數據交給操作系統來處理,由操作系統來決定什么時候同步數據。更快,也更不安全的選擇。
always、everysec、no對比
命令 | 優點 | 缺點 |
---|---|---|
always | 不丟失數據 | IO開銷大,一般SATA磁盤只有幾百TPS |
everysec | 每秒進行與fsync,最多丟失1秒數據 | 可能丟失1秒數據 |
no | 不用管 | 不可控 |
推薦(並且也是默認)的措施為每秒 fsync 一次, 這種 fsync 策略可以兼顧速度和安全性。
3. AOF重寫
因為 AOF 的運作方式是不斷地將命令追加到文件的末尾, 所以隨着寫入命令的不斷增加, AOF 文件的體積也會變得越來越大。舉個例子, 如果你對一個計數器調用了 100 次 INCR , 那么僅僅是為了保存這個計數器的當前值, AOF 文件就需要使用 100 條記錄(entry)。然而在實際上, 只使用一條 SET 命令已經足以保存計數器的當前值了, 其余 99 條記錄實際上都是多余的。
為了處理這種情況, Redis 支持一種有趣的特性: 可以在不打斷服務客戶端的情況下, 對 AOF 文件進行重建(rebuild)。執行 bgrewriteaof 命令, Redis 將生成一個新的 AOF 文件, 這個文件包含重建當前數據集所需的最少命令。
Redis 2.2 需要自己手動執行 bgrewriteaof 命令; Redis 2.4 則可以通過配置自動觸發 AOF 重寫。
AOF重寫的作用
- 減少磁盤占用量
- 加速數據恢復
AOF重寫的實現方式
-
bgrewriteaof 命令
Redis bgrewriteaof 命令用於異步執行一個 AOF(AppendOnly File)文件重寫操作。重寫會創建一個當前AOF文件的體積優化版本。
即使 bgrewriteaof 執行失敗,也不會有任何數據丟失,因為舊的AOF文件在 bgrewriteaof 成功之前不會被修改。
AOF 重寫由 Redis 自行觸發,bgrewriteaof 僅僅用於手動觸發重寫操作。
具體內容:- 如果一個子Redis是通過磁盤快照創建的,AOF重寫將會在RDB終止后才開始保存。這種情況下BGREWRITEAOF任然會返回OK狀態碼。從Redis 2.6起你可以通過INFO命令查看AOF重寫執行情況。
- 如果只在執行的AOF重寫返回一個錯誤,AOF重寫將會在稍后一點的時間重新調用。
- AOF重寫配置
配置名 | 含義 |
---|---|
auto-aof-rewrite-min-size | 觸發AOF文件執行重寫的最小尺寸 |
auto-aof-rewrite-percentage | 觸發AOF文件執行重寫的增長率 |
統計名 | 含義 |
---|---|
aof_current_size | AOF文件當前尺寸(字節) |
aof_base_size | AOF文件上次啟動和重寫時的尺寸(字節) |
AOF重寫自動觸發機制,需要同時滿足下面兩個條件:
- aof_current_size > auto-aof-rewrite-min-size
- (aof_current_size - aof_base_size) * 100 / aof_base_size > auto-aof-rewrite-percentage
假設 Redis 的配置項為:
auto-aof-rewrite-min-size 64mb
auto-aof-rewrite-percentage 100
當AOF文件的體積大於64Mb,並且AOF文件的體積比上一次重寫之久的體積大了至少一倍(100%)時,Redis將執行 bgrewriteaof 命令進行重寫。
AOF重寫的流程

3. AOF相關配置
# 開啟AOF持久化方式
appendonly yes
# AOF持久化文件名
appendfilename appendonly-<port>.aof
# 每秒把緩沖區的數據同步到磁盤
appendfsync everysec
# 數據持久化文件存儲目錄
dir /var/lib/redis
# 是否在執行重寫時不同步數據到AOF文件
# 這里的 yes,就是執行重寫時不同步數據到AOF文件
no-appendfsync-on-rewrite yes
# 觸發AOF文件執行重寫的最小尺寸
auto-aof-rewrite-min-size 64mb
# 觸發AOF文件執行重寫的增長率
auto-aof-rewrite-percentage 100
4. AOF的優點
- 使用AOF 會讓你的Redis更加耐久: 你可以使用不同的fsync策略:無fsync,每秒fsync,每次寫的時候fsync。使用默認的每秒fsync策略,Redis的性能依然很好(fsync是由后台線程進行處理的,主線程會盡力處理客戶端請求),一旦出現故障,你最多丟失1秒的數據。
- AOF文件是一個只進行追加的日志文件,所以不需要寫入seek,即使由於某些原因(磁盤空間已滿,寫的過程中宕機等等)未執行完整的寫入命令,你也也可使用redis-check-aof工具修復這些問題。
- Redis 可以在 AOF 文件體積變得過大時,自動地在后台對 AOF 進行重寫: 重寫后的新 AOF 文件包含了恢復當前數據集所需的最小命令集合。 整個重寫操作是絕對安全的,因為 Redis 在創建新 AOF 文件的過程中,會繼續將命令追加到現有的 AOF 文件里面,即使重寫過程中發生停機,現有的 AOF 文件也不會丟失。 而一旦新 AOF 文件創建完畢,Redis 就會從舊 AOF 文件切換到新 AOF 文件,並開始對新 AOF 文件進行追加操作。
- AOF 文件有序地保存了對數據庫執行的所有寫入操作, 這些寫入操作以 Redis 協議的格式保存, 因此 AOF 文件的內容非常容易被人讀懂, 對文件進行分析(parse)也很輕松。 導出(export) AOF 文件也非常簡單: 舉個例子, 如果你不小心執行了 FLUSHALL 命令, 但只要 AOF 文件未被重寫, 那么只要停止服務器, 移除 AOF 文件末尾的 FLUSHALL 命令, 並重啟 Redis , 就可以將數據集恢復到 FLUSHALL 執行之前的狀態。
5. AOF的缺點
- 對於相同的數據集來說,AOF 文件的體積通常要大於 RDB 文件的體積。
- 根據所使用的 fsync 策略,AOF 的速度可能會慢於 RDB 。 在一般情況下, 每秒 fsync 的性能依然非常高, 而關閉 fsync 可以讓 AOF 的速度和 RDB 一樣快, 即使在高負荷之下也是如此。 不過在處理巨大的寫入載入時,RDB 可以提供更有保證的最大延遲時間(latency)。
四、RDB和AOF的抉擇
1. RDB 和 AOF 對比
----- | RDB | AOF |
---|---|---|
啟動優先級 | 低 | 高 |
體積 | 小 | 大 |
恢復速度 | 快 | 慢 |
數據安全性 | 丟數據 | 根據策略決定 |
2. 如何選擇使用哪種持久化方式?
一般來說, 如果想達到足以媲美 PostgreSQL 的數據安全性, 你應該同時使用兩種持久化功能。
如果你非常關心你的數據, 但仍然可以承受數分鍾以內的數據丟失, 那么你可以只使用 RDB 持久化。
有很多用戶都只使用 AOF 持久化, 但並不推薦這種方式: 因為定時生成 RDB 快照(snapshot)非常便於進行數據庫備份, 並且 RDB 恢復數據集的速度也要比 AOF 恢復的速度要快。
.
