Redis 有兩種持久化方案,RDB (Redis DataBase)和 AOF (Append Only File)。
RDB
RDB 是 Redis 默認的持久化方案。在指定的時間間隔內(週期性),執行指定次數的寫操作,則會將內存中的數據寫入到磁盤中。即在指定目錄下生成一個dump.rdb文件。Redis 重啓會通過加載dump.rdb文件恢復數據。觸發RDB持久化過程分爲手動觸發和自動觸發。
相關的命令使用
save命令: 阻塞當前Redis服務器, 直到RDB過程完成爲止, 對於內存比較大的實例會造成長時間阻塞, 線上環境不建議使用。
bgsave命令: Redis進程執行fork操作創建子進程, RDB持久化過程由子進程負責, 完成後自動結束。
壓縮
優缺點
-
RDB是一個緊湊壓縮的二進制文件, 代表Redis在某個時間點上的數據快照。 非常適用於備份, 全量複製等場景。
-
Redis加載RDB恢復數據遠遠快於AOF的方式。
-
RDB方式數據沒辦法做到實時持久化/秒級持久化。 因爲bgsave每次運行都要執行fork操作創建子進程, 屬於重量級操作, 頻繁執行成本過高。
-
RDB文件使用特定二進制格式保存, Redis版本演進過程中有多個格式的RDB版本, 存在老版本Redis服務無法兼容新版RDB格式的問題。
AOF
優缺點
AOF的具體流程:
-
所有的寫入命令會追加到aof_buf(緩衝區) 中。
-
AOF緩衝區根據對應的策略向硬盤做同步操作。
-
隨着AOF文件越來越大, 需要定期對AOF文件進行重寫, 達到壓縮的目的。
-
當Redis服務器重啓時, 可以加載AOF文件進行數據恢復。
AOF緩衝區同步文件策略
-
always---命令寫入aof_buf後調用系統fsync操作同步到AOF文件,fsync完成後線程使用。效率較低。不建議配置
-
everysec---命令寫入aof_buf後調用系統write操作,write完成後線程返回。fsync同步文件操作由專門線程每秒調用一次。默認配置-兼顧性能和安全性,理論上只有在系統突然宕機的情況下丟失1秒的數據。
-
no---命令寫入aof_buf後調用系統write操作,不對AOF文件做fsync同步,同步硬盤操作由操作系統負責,通常同步週期最常30秒。數據安全性無法保證
AOF的write操作和fsync操作
-
write操作會觸發延遲寫(delayed write) 機制。 Linux在內核提供頁緩衝區用來提高硬盤IO性能。 write操作在寫入系統緩衝區後直接返回。 同步硬盤操作依賴於系統調度機制, 例如: 緩衝區頁空間寫滿或達到特定時間週期。同步文件之前, 如果此時系統故障宕機, 緩衝區內數據將丟失。
-
fsync針對單個文件操作(比如AOF文件) , 做強制硬盤同步, fsync將阻塞直到寫入硬盤完成後返回, 保證了數據持久化。
AOF重寫機制
-
進程內已經超時的數據不再寫入文件。
-
舊的AOF文件含有無效命令。
-
多條寫命令可以合併爲一個。
Redis重寫AOF或RDB文件時出現的問題:
1.fork操作
當Redis做RDB或AOF重寫時, 一個必不可少的操作就是執行fork操作創建子進程, 對於大多數操作系統來說fork是個重量級操作。 雖然fork創建的子進程不需要拷貝父進程的物理內存空間, 但是會複製父進程的空間內存頁表。 例如對於10GB的Redis進程, 需要複製大約20MB的內存頁表, 因此fork操作耗時跟進程總內存量息息相關, 如果使用虛擬化技術, 特別是Xen虛擬機, fork操作會更耗時。
fork耗時問題定位: 對於高流量的Redis實例OPS可達5萬以上, 如果fork操作耗時在秒級別將拖慢Redis幾萬條命令執行, 對線上應用延遲影響非常明顯。 正常情況下fork耗時應該是每GB消耗20毫秒左右。 可以在info stats統計中查latest_fork_usec指標獲取最近一次fork操作耗時, 單位微秒。
如何改善fork操作的耗時:
1) 優先使用物理機或者高效支持fork操作的虛擬化技術, 避免使用Xen。
2) 控制Redis實例最大可用內存, fork耗時跟內存量成正比, 線上建議每個Redis實例內存控制在10GB以內。
3) 合理配置Linux內存分配策略, 避免物理內存不足導致fork失敗, 具體細節見12.1節“Linux配置優化”。
4) 降低fork操作的頻率, 如適度放寬AOF自動觸發時機, 避免不必要的全量複製等。
2.AOF追加阻塞
同步硬盤的策略是everysec, 用於平衡性能和數據安全性。 對於這種方式, Redis使用另一條線程每秒執行fsync同步硬盤。 當系統硬盤資源繁忙時, 會造成Redis主線程阻塞。
阻塞流程分析:
1) 主線程負責寫入AOF緩衝區。
2) AOF線程負責每秒執行一次同步磁盤操作, 並記錄最近一次同步時間。
3) 主線程負責對比上次AOF同步時間:
-
如果距上次同步成功時間在2秒內, 主線程直接返回。
-
如果距上次同步成功時間超過2秒, 主線程將會阻塞, 直到同步操作完成。
通過對AOF阻塞流程可以發現兩個問題:
1) everysec配置最多可能丟失2秒數據, 不是1秒。
2) 如果系統fsync緩慢, 將會導致Redis主線程阻塞影響效率。
AOF阻塞問題定位:
1) 發生AOF阻塞時, Redis輸出如下日誌, 用於記錄AOF fsync阻塞導致拖慢Redis服務的行爲:
Asynchronous AOF fsync is taking too long (disk is busy). Writing the AOF buffer without waiting for fsync to complete, this may slow down Redis
2) 每當發生AOF追加阻塞事件發生時, 在info Persistence統計中,aof_delayed_fsync指標會累加, 查看這個指標方便定位AOF阻塞問題。
3) AOF同步最多允許2秒的延遲, 當延遲發生時說明硬盤存在高負載問題(優化系統硬盤負載即可), 可以通過監控工具如iotop, 定位消耗硬盤IO資源的進程。