單點 Redis 的一些問題
- 數據丟失:Redis 是內存存儲,服務重啟可能會丟失數據。solution:實現 Redis 數據持久化。
- 并發能力:單節點 Redis 并發能力雖然不錯,但也無法滿足如618這樣的高并發場景。solution:搭建主從集群,實現讀寫分離。
- 故障恢復:如果 Redis 宕機,則服務不可用,需要一種自動的故障恢復手段。solution:哨兵機制,實現健康檢測及自動恢復。
- 存儲能力:Redis 基于內存,單節點能存儲的數據量難以滿足海量數據需求。solution:搭建分片集群,利用插槽機制實現動態擴容。
Redis 持久化
- 使用緩存的時候,我們經常需要對內存中的數據進行持久化也就是將內存中的數據寫入到硬盤中。大部分原因是為了之后重用數據(比如重啟機器、機器故障之后恢復數據),或者是為了做數據同步(比如 Redis 集群的主從節點通過 RDB 文件同步數據)。
- Redis 不同于 Memcached 的很重要一點就是,Redis 支持持久化,而且支持 3 種持久化方式:快照(snapshotting,RDB、只追加文件(append-only file, AOF)、以及RDB 和 AOF 的混合持久化(Redis 4.0 新增)。
1.RDB
- RDB 全稱 Redis Database Backup file(Redis數據備份文件),也被叫做 Redis 數據快照。
- 簡單來說就是把內存中某個時間點的所有數據都記錄到磁盤中。當 Redis 實例故障重啟后,從磁盤讀取快照文件,恢復數據。快照文件稱為 RDB 文件,默認是保存在當前運行目錄。
執行 RDB
- 誰來執行?
save
命令:由 Redis 主進程來執行 RDB,會阻塞所有命令。bgsave
命令:開啟子進程執行 RDB,避免主進程受到影響。默認選項。bgsave
開始時會 fork 主進程得到子進程,子進程共享主進程的內存數據。完成 fork 后讀取內存數據并寫入新的 RDB 文件替換舊的。- fork 采用的是 copy-on-write 技術:當主進程執行讀操作時,訪問共享內存;當主進程執行寫操作時,則會拷貝一份數據,執行寫操作。
- 何時執行?
- Redis 停機時會自動執行一次 RDB。
- Redis 內部有觸發 RDB 的機制,可以在 redis.conf 文件中找到,如:
save 900 1
表示900秒內,如果至少有1個 key 被修改,則執行bgsave
, save ""
則表示禁用 RDB。
RDB 缺點
- RDB 執行間隔時間長,兩次 RDB 之間去寫入數據有丟失的風險。
- fork 子進程、壓縮、寫出 RDB 文件都比較耗時。
2.AOF
- AOF 全稱 Append Only File(追加文件)。Redis 處理的每一個寫命令,都會將該命令寫入到 AOF 緩沖區中,然后再寫入AOF 文件,可以看做是命令日志文件。
執行 AOF
-
執行流程?
- 命令追加(append):所有的寫命令會追加到 AOF 緩沖區中。
- 文件寫入(write):將 AOF 緩沖區的數據寫入到 AOF 文件中。這一步需要調用write函數(系統調用),write將數據寫入到了系統內核緩沖區之后直接返回了(延遲寫)。注意!!!此時并沒有同步到磁盤。
- 文件同步(fsync):AOF 緩沖區根據對應的持久化方式( fsync 策略)向硬盤做同步操作。這一步需要調用 fsync 函數(系統調用), fsync 針對單個文件操作,對其進行強制硬盤同步,fsync 將阻塞直到寫入磁盤完成后返回,保證了數據持久化。
- 文件重寫(rewrite):隨著 AOF 文件越來越大,需要定期對 AOF 文件進行重寫,達到壓縮的目的。
- 重啟加載(load):當 Redis 重啟時,可以加載 AOF 文件進行數據恢復。
-
誰來執行?
- AOF 默認是關閉的。需要修改 redis.conf 配置文件來開啟 AOF。
- AOF 默認是關閉的。需要修改 redis.conf 配置文件來開啟 AOF。
-
何時執行?
- AOF 的命令記錄頻率也可以通過 redis.conf 文件來配置。默認每隔一秒記錄一次。
- AOF 的命令記錄頻率也可以通過 redis.conf 文件來配置。默認每隔一秒記錄一次。
AOF 自動重寫功能
- AOF 重寫(rewrite) 是一個有歧義的名字,該功能是通過讀取數據庫中的鍵值對來實現的,程序無須對現有 AOF 文件進行任何讀入、分析或者寫入操作。
- 因為記錄的是命令,AOF 文件會比 RDB 文件大的多。而且AOF會記錄對同一個key的多次寫操作,但只有最后一次寫操作才有意義。通過執行
bgrewriteaof
命令,可以讓AOF文件執行重寫功能,用最少的命令達到相同效果。 - AOF 文件重寫期間,Redis 還會維護一個 AOF 重寫緩沖區,該緩沖區會在子進程創建新 AOF 文件期間,記錄服務器執行的所有寫命令。當子進程完成創建新 AOF 文件的工作之后,服務器會將重寫緩沖區中的所有內容追加到新 AOF 文件的末尾,使得新的 AOF 文件保存的數據庫狀態與現有的數據庫狀態一致。最后,服務器用新的 AOF 文件替換舊的 AOF 文件,以此來完成 AOF 文件重寫操作。
- Redis 也會在觸發閾值時自動去重寫 AOF 文件。值也可以在redis.conf中配置。
AOF 為什么是在執行完命令之后記錄日志?
- 避免額外的檢查開銷,AOF 記錄日志不會對命令進行語法檢查;
- 在命令執行完之后再記錄,不會阻塞當前的命令執行。
- 這樣也帶來了風險:
- 如果剛執行完命令 Redis 就宕機會導致對應的修改丟失;
- 可能會阻塞后續其他命令的執行(AOF 記錄日志是在 Redis 主線程中進行的)。
AOF 校驗機制
- 純 AOF 模式下,Redis 通過逐條解析文件中的命令來驗證文件的有效性。
- 在 混合持久化模式(Redis 4.0 引入)下,AOF 文件由兩部分組成:
- RDB 快照部分:文件以固定的 REDIS 字符開頭,存儲某一時刻的內存數據快照,并在快照數據末尾附帶一個 CRC64 校驗和(位于 RDB 數據塊尾部、AOF 增量部分之前)。
- AOF 增量部分:緊隨 RDB 快照部分之后,記錄 RDB 快照生成后的增量寫命令。這部分增量命令以 Redis 協議格式逐條記錄,無整體或全局校驗和。
- Redis 啟動并加載 AOF 文件時,首先會校驗文件開頭 RDB 快照部分的數據完整性,即計算該部分數據的 CRC64 校驗和,并與緊隨 RDB 數據之后、AOF 增量部分之前存儲的 CRC64 校驗和值進行比較。如果 CRC64 校驗和不匹配,Redis 將拒絕啟動并報告錯誤。
- RDB 部分校驗通過后,Redis 隨后逐條解析 AOF 部分的增量命令。如果解析過程中出現錯誤(如不完整的命令或格式錯誤),Redis 會停止繼續加載后續命令,并報告錯誤,但此時 Redis 已經成功加載了 RDB 快照部分的數據。
RDB 與 AOF
- RDB 和 AOF 各有自己的優缺點。
- 如何選擇?
- 如果 Redis 保存的數據丟失一些也沒什么影響的話,可以選擇使用 RDB。
- 不建議單獨使用 AOF,因為時不時地創建一個 RDB 快照可以進行數據庫備份、更快的重啟以及解決 AOF 引擎錯誤。
- 如果數據要求的安全性比較高的話,建議同時開啟 RDB 和 AOF 持久化或者開啟 RDB 和 AOF 混合持久化。