文章目錄
- Redis 持久化
- 一、RDB
- 1.1 說明
- 1.2 觸發機制
- 手動觸發
- 自動觸發
- 1.3 流程說明
- 1.4 文件處理
- 1.5 優缺點 & 適用場景
- 二、AOF
- 2.1 說明
- 2.2 使用 AOF
- 2.3 命令寫入
- 2.4 文件同步
- 2.5 重寫機制
- 2.6 啟動時數據恢復
- 2.7 優缺點 & 適用場景
- 三、不使用 AOF / RDB 的情況
- 3.1 場景
- 3.2 實現方案
Redis 持久化
Redis 本身是作用與內存中的數據庫,所以必須考慮數據持久化問題(將內存中的數據存儲到硬盤中)。
Redis 支持 RDB 與 AOF 兩種持久化機制,持久化功能有效地避免因進程退出造成數據丟失問題,當下次重啟時利用之前持久化的文件可以實現數據恢復。
一、RDB
1.1 說明
- RDB 持久化是 Redis 默認的持久化方式,通過 快照(snapshot)來持久化數據。
- 即把當前進程數據生成快照保存到硬盤的過程、觸發RDB持久化過程分為手動觸發與自動觸發。
- Redis 會在指定的時間間隔內生成數據的快照并保存在磁盤中(RDB 文件),通常是 .rdb 文件。(自動觸發)、也可以手動執行命令進行手動觸發
1.2 觸發機制
手動觸發
手動觸發分別對應 save
與 bgsave
命令:
- SAVE:會阻塞 Redis 主進程,直到 RDB 持久化完成。這個命令會在當前進程中執行持久化操作,執行過程中 Redis 會暫停所有請求,直到數據保存完成。
- 但是對于內存較大的實例會造成長時間阻塞,基本不采用。
- BGSAVE :在后臺異步執行RDB持久化,Redis 會生成一個子進程來執行持久化操作,主進程可以繼續處理請求。執行 BGSAVE 時,Redis 會創建一個子進程來保存數據并生成 RDB 文件。
- 阻塞只發生在 fork 階段,一般時間很短。
Redis 內部所有涉及 RDB 的操作都類似 bgsave 的方式。
自動觸發
Redis 運行自動觸發 RDB 持久化機制,該機制在實際環境中更實用。
Redis 默認的 RDB 持久化是基于時間和寫操作的觸發條件。可以通過 redis.conf 配置文件中的 save 參數設置自動觸發的條件。
-
使用
save
配置。如“save m n
” 表示 m 秒內數據集發生了 n 次修改,自動 RDB 持久化。比如:save 900 1 # 900秒(15分鐘)內至少有1次寫操作時觸發RDB save 300 10 # 300秒(5分鐘)內至少有10次寫操作時觸發RDB save 60 10000 # 60秒內至少有10000次寫操作時觸發RDB
-
從節點進行全量復制操作時,主節點自動進行RDB持久化,隨后將RDB文件內容發送給從節點。
-
執行
shutdown
命令關閉 Redis 時,執行 RDB 持久化。
比如在redis.conf
的這個位置(內存管理)進行save
配置:
1.3 流程說明
BGSAVE
是主流的 RDB 持久化方式,下圖演示了其運作流程:
-
執行
bgsave
命令時,Redis 父進程首先會檢查是否已有其他子進程正在執行,如 RDB 或 AOF 子進程。如果存在其他子進程,bgsave
命令將直接返回,不會執行。 -
父進程執行
fork
創建子進程,在fork
過程中,父進程會阻塞。可以通過執行INFO stats
命令并查看latest_fork_usec
選項,獲取最近一次fork
操作的耗時,單位為微秒。 -
fork
完成后,父進程不再阻塞,bgsave
命令返回 “Background saving started” 信息,表示子進程開始生成 RDB 文件,同時父進程可以繼續處理其他命令。 -
子進程生成 RDB 文件,它會根據父進程的內存內容生成一個臨時快照文件,并在完成后將原有文件替換為新生成的 RDB 文件。可以通過執行
lastsave
命令來獲取最后一次成功生成 RDB 文件的時間,信息也會在INFO
統計的rdb_last_save_time
選項中顯示。 -
子進程完成任務后,發送信號給父進程,通知父進程操作已完成。隨后,父進程會更新相關的統計信息。
1.4 文件處理
-
保存:RDB 文件會保存在通過
dir
配置指定的目錄中(默認目錄為/var/lib/redis/
),文件名通過dbfilename
配置指定(默認文件名為dump.rdb
)。可以通過執行config set dir {newDir}
和config set dbfilename {newFilename}
動態修改目錄和文件名設置。當 Redis 重啟時,RDB 文件會保存到新的目錄。 -
壓縮:Redis 默認使用 LZF 算法對生成的 RDB 文件進行壓縮處理,壓縮后的文件體積遠小于內存大小。默認情況下,壓縮是開啟的,可以通過
config set rdbcompression {yes|no}
動態修改壓縮設置。
提示:雖然開啟 RDB 壓縮會消耗一定的 CPU 資源,但可以顯著減小文件大小,方便將文件保存到硬盤或通過網絡發送到從節點,因此建議開啟壓縮功能。
- 校驗:如果 Redis 在啟動時加載到損壞的 RDB 文件,啟動會失敗。此時,可以使用 Redis 提供的
redis-check-dump
工具檢測 RDB 文件,并獲取相應的錯誤報告。
1.5 優缺點 & 適用場景
優點:
- RDB 是一個緊湊壓縮的二進制文件,代表 Redis 某個時間點上的數據快照,適用于備份、全量復制等場景。比如每6h執行 bgsave 備份,并把RDB文件復制到遠程及其或者文件系統中(如hdfs)。
- Redis 加載 RDB 數據遠快于 AOF。在重啟Redis時恢復速度較快。
- RDB 文件是壓縮格式,能夠節省存儲空間。
缺點:
- RDB 方式數據無法做到 實時持久化 / 秒級持久化。因為 bgsave 每次運行都會執行 fork 創建子進程,開銷較大,頻繁執行成本過高。
- RDB 文件使用特定二進制格式保存、Redis 版本演進過程中有多個 RDB 版本,兼容性可能存在風險。
- 數據丟失風險較大:RDB 是基于時間間隔的快照,如果在快照之間發生了 Redis 崩潰,則會丟失在最后一次快照之后的所有數據。
適用場景:
適合用于備份和災難恢復,尤其是對于不要求非常實時的數據恢復場景。
二、AOF
2.1 說明
AOF(Append Only File)持久化:
以獨立日志的方式記錄每次寫命令,重啟時再重新執行 AOF 文件中的命令,以達到恢復數據的目的。AOF 主要作用是解決了數據持久化的實時性。
AOF 文件中的內容是 Redis 執行的所有寫命令的日志,這些命令可以用來重建數據庫狀態,目前已經是Redis持久化的主流方式。
2.2 使用 AOF
開啟 AOF 功能需要設置配置:appendonly yes
,默認是不開啟的。
AOF 文件名通過 appendfilename
配置指定,默認值為 appendonly.aof
,其保存目錄與 RDB 持久化方式一致,可通過 dir
配置進行設置。
AOF 的工作流程包括:命令寫入(append)、文件同步(sync)、文件重寫(rewrite)、重啟加載(load)。
AOF 工作流程如下圖所示:
對上圖工作流程的解釋:
- 所有寫入命令會被追加到 AOF 緩沖區(
aof_buf
)中。 - 根據配置的同步策略,AOF 緩沖區會定期將數據同步到硬盤。
- 隨著 AOF 文件增大,Redis 會定期進行文件重寫,以壓縮文件并減小磁盤占用。
- 當 Redis 重啟時,可以通過加載 AOF 文件來恢復數據。
2.3 命令寫入
AOF 命令寫入的內容是文本協議格式,如 set hello world
,在AOF緩沖區中會追加的是:
*3\r\n$3\r\nset\r\n$5\r\nhello\r\n$5\r\nworld\r\n
此處遵守的是 Redis 格式協議,Redis 選擇的是文本協議,可能有以下原因:
- 實現簡單
- 文本協議比二進制協議更加容易實現
- 簡單性和可讀性
- 數據以純文本的形式傳輸,格式簡單且直觀,用戶可以很容易地查看和調試通信內容
- 兼容性
- 文本協議的另一個優點是它具有較高的跨平臺兼容性。所有主流的操作系統和編程語言都可以輕松地處理文本數據
AOF 過程中為什么需要 aof_buf
緩沖區?
- 我們知道,Redis使用單線程響應命令,如果每次寫 AOF 文件都直接同步硬盤,從內存的讀寫變為IO讀寫,性能必然下降。先寫入緩沖區可以有效減少 IO 次數,同時 Redis 還可以提供多種緩沖區策略,讓用戶根據自己的需求做出合理的平衡。
2.4 文件同步
Redis 提供了多種 AOF 緩沖區同步文件策略,使用參數 appendfsync
控制。不同配置值的含義如下表所示:
表 4-1 AOF 緩沖區同步文件策略
可配置值 | 說明 |
---|---|
always | 每次命令寫入 aof_buf 后都調用 fsync 同步,完成后返回。 |
everysec | 命令寫入 aof_buf 后執行 write 操作,不進行 fsync 。每秒由同步線程執行 fsync 。 |
no | 命令寫入 aof_buf 后執行 write 操作,由操作系統控制 fsync 的頻率。 |
系統調用 write
和 fsync
的說明:
write
操作:觸發延遲寫(delayed write)機制。Linux 內核使用頁緩沖區提高硬盤 I/O 性能。write
操作將數據寫入系統緩沖區后立即返回,實際的硬盤同步依賴系統調度機制,例如緩沖區滿或達到時間周期。若系統發生故障或宕機,未同步的數據可能丟失。fsync
操作:對單個文件進行強制硬盤同步,直到數據寫入硬盤前,fsync
會阻塞。
配置說明:
always
配置:每次寫入時都會同步 AOF 文件,性能較差。在普通的 SATA 硬盤上,通常只能支持幾百 TPS 寫入。除非數據至關重要,否則不推薦使用此配置。no
配置:由于操作系統同步策略不可控,性能較高,但數據丟失的風險大增。除非數據不重要,否則不推薦使用。everysec
配置:為默認配置,也是推薦配置,兼顧了數據安全性與性能。理論上最多丟失 1 秒的數據,適用于大多數場景。
2.5 重寫機制
隨著 Redis 持續將命令寫入 AOF 文件,文件體積會不斷增大。為了優化存儲和性能,Redis 引入了 AOF 重寫機制,它會壓縮 AOF 文件的體積。
AOF 重寫的過程是將 Redis 進程內的數據轉換為寫命令,并同步到新的 AOF 文件中。
為什么重寫后的 AOF 文件會變小? 主要原因如下:
- 剔除超時數據:進程內已經超時的數據不會寫入重寫后的文件。
- 刪除無效命令:舊 AOF 文件中的無效命令(如
del
、hdel
、srem
等)會在重寫時被刪除,僅保留數據的最終狀態。 - 合并多個寫操作:多個連續的寫操作可以合并成一條命令。例如,
lpush list a
、lpush list b
、lpush list c
可以合并為lpush list a b c
。
重寫后的 AOF 文件較小,既降低了硬盤的空間占用,又能提高 Redis 啟動時的數據恢復速度。
AOF 重寫過程可以通過手動和自動兩種方式觸發:
- 手動觸發:使用
bgrewriteaof
命令。 - 自動觸發:根據
auto-aof-rewrite-min-size
和auto-aof-rewrite-percentage
參數自動觸發重寫。auto-aof-rewrite-min-size
:定義觸發重寫時 AOF 文件的最小大小,默認為 64MB。auto-aof-rewrite-percentage
:定義當前 AOF 文件大小相對于上次重寫時增加的比例。
AOF 重寫的執行流程:
-
執行 AOF 重寫請求:
如果當前進程正在執行 AOF 重寫,新的請求會被延遲。如果當前正在執行bgsave
操作,重寫命令會等到bgsave
完成后再執行。 -
父進程執行
fork
創建子進程:
父進程會通過fork
創建子進程進行重寫操作。 -
重寫過程:
- a. 父進程在
fork
后繼續響應其他命令,所有修改操作都會寫入 AOF 緩沖區,并根據appendfsync
策略同步到硬盤,確保舊 AOF 文件的數據完整性。 - b. 子進程只有在
fork
之前的內存數據,父進程中的修改操作會被寫入 AOF 重寫緩沖區。
- a. 父進程在
-
子進程重寫 AOF 文件:
子進程根據內存快照,將命令合并并寫入新的 AOF 文件中。 -
完成重寫:
- a. 子進程寫入新文件后,發送信號給父進程。
- b. 父進程將 AOF 重寫緩沖區內臨時保存的命令追加到新 AOF 文件中。
- c. 父進程用新生成的 AOF 文件替換舊的 AOF 文件。
通過上述重寫機制,Redis 能有效優化 AOF 文件的體積,提升性能并減少存儲消耗。
2.6 啟動時數據恢復
當 Redis 啟動時,會根據 RDB 和 AOF 文件的內容,進行數據恢復。
2.7 優缺點 & 適用場景
優點:
- AOF 可以實現更高的持久化安全性,相比于 RDB,它更能保證數據不丟失。
- 如果 Redis 崩潰,可以從 AOF 文件恢復到最后一個寫操作。
- 可設置不同的同步策略,以實現平衡的性能和持久化保障。
缺點:
- AOF 文件比 RDB 文件更大,因為它記錄的是每個寫操作的日志,可能會占用更多磁盤空間。
- 寫操作會稍微慢一些,因為每次寫入命令都要追加到 AOF 文件中,雖然可以通過異步寫入來緩解性能問題。
- AOF 恢復數據時的速度較慢,因為需要重放所有寫命令。
適用場景:
AOF 適合用于要求較高數據持久性的場景,例如需要盡量避免數據丟失的應用。
三、不使用 AOF / RDB 的情況
3.1 場景
在實際業務場景下,如果不使用 AOF 或 RDB,Redis 可以與 MySQL 等外部數據庫結合,來實現數據的持久化。這種方案通常適用于以下情況:
-
緩存加速 + 持久化分離
- 特點:
- Redis 作為高性能緩存,MySQL 作為真實數據源。
- 適合讀多寫少的業務(如商品詳情頁、用戶畫像)。
- 同步策略:
- 讀:優先讀 Redis,未命中則查 MySQL 并回填。
- 寫:直接寫 MySQL,并刪除/更新 Redis 緩存(Cache-Aside 模式)。
- 特點:
-
臨時數據 + 永久存儲分離
- 特點:
- Redis 存儲短期高頻數據(如會話、排行榜),MySQL 存儲長期數據。
- 適合時效性數據(如 30 天內的訂單狀態)。
- 同步策略:
- 通過 TTL 自動清理 Redis 數據,關鍵數據異步歸檔到 MySQL。
- 特點:
-
高并發寫入緩沖
- 特點:
- 用 Redis 緩沖突發寫入(如秒殺庫存),再平滑同步到 MySQL。
- 適合寫密集型業務(如點擊計數、日志采集)。
- 同步策略:
- Redis 累加計數,每小時同步一次聚合結果到 MySQL。
- 特點:
3.2 實現方案
-
雙寫模式(Write-Through)
- 機制:
應用同時寫入 Redis 和 MySQL,保持雙數據源一致。def set_user(user_id, data):# 同步寫 MySQLmysql.execute("REPLACE INTO users VALUES (%s, %s)", (user_id, data))# 寫 Redisredis.set(f"user:{user_id}", data)
- 優點:強一致性
- 缺點:寫入性能下降,需處理事務回滾(如 MySQL 失敗需回滾 Redis)。
- 機制:
-
異步同步(Write-Behind)
- 機制:
先寫 Redis,再通過消息隊列或定時任務異步同步到 MySQL。def set_user(user_id, data):redis.set(f"user:{user_id}", data)# 發送到消息隊列(如 Kafka/RabbitMQ)mq.publish("user_update", {"id": user_id, "data": data})# 消費者異步處理 MySQL 寫入
- 優點:高性能,解耦
- 缺點:存在短暫不一致窗口。
- 機制:
-
定時批量同步
- 機制:
定期掃描 Redis 數據批量寫入 MySQL(適合冷數據)。-- MySQL 表設計示例 CREATE TABLE redis_backup (`key` VARCHAR(255) PRIMARY KEY,`value` TEXT,`expire_time` DATETIME );
- 機制: