首先介紹RDB和AOF的配置和運行過程,以及控制持久化的相關命令,如bgsave和bgrewriteaof。
其次,對常見的持久性問題進行分析、定位和優化。
最後結合Redis常見的單機多實例部署場景進行優化。
5.1 RDB
RDB持久化是將當前進程數據生成的快照保存到硬盤的過程。RDB持續的觸發過程可以分為手動觸發和自動觸發。
5.1.1觸發機制
分別手動觸發save和bgsave命令:
save命令:阻塞當前Redis服務器,直到RDB進程完成,這將導致大內存實例的長期阻塞,不建議在線環境使用。運行save命令進行對應。
Redis的日誌如下:
*數據庫保存在磁盤上
bgsave命令:Redis進程執行fork操作創建子進程,子進程負責RDB持久化進程,完成後自動結束。堵塞只發生在分叉階段,壹般時間很短。與運行bgsave命令相對應的Redis日誌如下:
*後臺保存由pid 3151啟動
*數據庫保存在磁盤上
* RDB:寫入時復制使用0 MB內存
*後臺保存成功終止
顯然,bgsave命令針對存儲阻塞問題進行了優化。因此Redis中所有涉及RDB的操作都采用bgsave的方式,save命令已經被放棄。
除了執行命令的手動觸發之外,Redis內部還有壹個自動觸發RDB的持久機制,例如下面的場景:
1)使用保存相關配置,比如“保存m n”。這意味著當m秒內數據集中有n次修改時,將自動觸發bgsave。
2)如果從節點進行全拷貝操作,主節點自動執行bgsave生成RDB文件並發送給從節點。有關更多詳細信息,請參見第6.3節中介紹的復制原理。
3)執行debug reload命令重載Redis時,也會自動觸發保存操作。
4)默認執行關機命令時,如果沒有打開AOF持久功能,將自動執行bgsave。
5.1.2流程描述
Bgsave是觸發RDB持久性的主流方式。我們根據圖5-1來了解壹下它的操作流程。
1)執行bgsave命令,Redis的父進程判斷是否有正在執行的子進程,比如RDB/AOF子進程,如果有bgsave命令直接返回。
2)父進程執行fork操作創建子進程,父進程在fork操作過程中會發生阻塞。通過info stats命令檢查latest_fork_usec選項,以獲取最近壹次fork操作的時間消耗,單位為微秒。
3)父進程的fork完成後,bgsave命令返回“後臺保存開始”的信息,可以繼續響應其他命令,不會阻塞父進程。
4)子進程創建RDB文件,根據父進程的內存生成臨時快照文件,完成後對原文件進行原子替換。執行lastsave命令獲取生成RDB的最後時間,對應於info statistics的rdb_last_save_time選項。
5)該過程向父過程發送信號以指示完成,並且父過程更新統計信息。有關詳細信息,請參見info Persistence下的rdb_*相關選項。
5.1.3 RDB文件的處理
保存:RDB文件保存在dir配置指定的目錄下,文件名由dbfilename配置指定。可以通過執行config set dir{newDir}和configsetdbfilename { new filename }運行時來動態執行,下次運行時RDB文件會保存到壹個新的目錄下。
操作和維護技巧
在壞盤或滿盤的情況下,可以通過config set dir{newDir}在線修改文件路徑為可用的磁盤路徑,然後執行bgsave切換磁盤,這也適用於AOF持久文件。
壓縮:Redis默認使用LZF算法壓縮生成的RDB文件。壓縮文件比內存大小小得多,默認情況下是打開的。它可以通過參數配置集RDB壓縮{yes | no}進行動態修改。
操作和維護技巧
壓縮RDB雖然會消耗CPU,但是可以大大減小文件大小,方便保存到硬盤或者通過網絡發送到從節點,建議在線打開。
驗證:如果Redis在加載損壞的RDB文件時拒絕啟動,則打印以下日誌:
#短讀取或OOM加載數據庫。不可恢復的錯誤,現在中止。
此時,您可以使用redis提供的redis-check-dump工具來檢測RDB文件,並獲得相應的錯誤報告。
5.1.4 RDB的優缺點
RDB的優勢:
RDB是壹個緊湊的二進制文件,它代表Redis數據在某個時間點的快照。非常適合備份、全拷貝等場景。例如,每6小時執行壹次bgsave備份,並將RDB文件復制到遠程機器或文件系統(如hdfs)用於災難恢復。
Redis加載RDB恢復數據的速度比AOF快得多。
RDB的缺點:
RDB模式數據無法實時/以秒為單位保存。因為bgsave每次運行都要執行fork操作來創建子進程,這是壹個重量級的操作,頻繁執行的成本太高。
RDB文件以特定的二進制格式保存。在Redis版本的演進過程中,有許多不同格式的RDB版本,因此舊版本的Redis服務與新的RDB格式不兼容。針對RDB不適合實時持久化的問題,Redis提供了AOF持久化來解決。
5.2 AOF
AOF(僅附加文件)持久性:在獨立的日誌中記錄每個寫命令,然後在重新啟動以恢復數據時重新執行AOF文件中的命令。AOF的主要功能是解決數據持久化的實時性問題,已經成為Redis持久化的主流方式。了解和掌握AOF的持久化機制,對於我們兼顧數據安全和性能非常有幫助。
使用AOF
要啟用AOF功能,需要設置配置:appendonly yes,默認情況下不啟用。AOF文件名通過appendfilename配置設置,默認文件名為appendonly.aof,保存路徑與RDB持久化壹致,通過dir配置指定。AOF的工作流操作:命令寫入(append)、文件同步(sync)、文件重寫(rewrite)、重啟加載(load),如圖5-2所示。
1)所有寫命令都將被附加到aof_buf(緩沖區)中。
2)2)AOF緩沖區根據相應的策略對硬盤進行同步操作。
3)隨著AOF文件越來越大,需要定期重寫AOF文件以達到壓縮的目的。
Redis服務器重啟後,可以加載AOF文件進行數據恢復。了解了AOF的工作流程後,下面是對每個步驟的詳細介紹。
命令書寫
AOF命令編寫的內容直接采用文本協議格式。例如,命令集hello world將在AOF緩沖區中追加以下文本:* 3 \ r \ n $ 3 \ r \ n set \ r \ n $ 5 \ r \ n Hello \ r \ n $ 5 \ r \ n World \ r \ n
Redis協議格式的詳細描述,請參考4.1客戶端協議章節,此處不再贅述。以下是介紹。
對AOF的兩點懷疑;
1)為什麽AOF直接采用文本協議格式?可能的原因如下:
文本協議具有良好的兼容性。
AOF開啟後,所有寫命令都包含附加操作,直接采用協議格式,避免了二次處理開銷。
文本協議可讀性強,便於直接修改和處理。
2)為什麽AOF把這個命令附加到aof_buf後面?Redis使用單線程來響應命令。如果寫入AOF文件的每個命令都直接附加到硬盤上,那麽性能完全取決於當前的硬盤負載。先寫入緩沖區aof_buf還有壹個好處。Redis可以提供多種緩沖區同步策略來平衡性能和安全性。
文件同步
Redis提供了多種AOF緩沖區同步文件策略,這些策略由參數appendfsync控制。不同值的含義如表5-1所示。
表5-1 AOF緩沖區同步文件策略
系統調用write和fsync的描述:
寫操作將觸發延遲寫機制。Linux在內核中提供了壹個頁面緩沖區來提高硬盤的IO性能。寫入操作在寫入系統緩沖區後直接返回。同步硬盤操作依賴於系統調度機制,比如:緩沖頁空間已滿或達到特定時間段。在同步文件之前,如果此時系統出現故障,緩沖區中的數據將會丟失。
Fsync對單個文件操作(如AOF文件)進行強制硬盤同步,FSYNC會壹直阻塞,直到寫入硬盤後返回,從而保證數據持久。除了write和fsync,Linux還提供了sync和fdatasync操作。詳見API描述。
請註意:這可能會降低redis的速度
2)每當aof附加阻塞事件發生時,aof_delayed_fsync指示符將在info持久性統計中累積,因此通過查看該指示符可以方便地定位AOF阻塞問題。
3)AOF同步最多允許2秒的延遲。出現延遲時,說明硬盤存在高負載問題。可以通過iotop等監控工具定位消耗硬盤IO資源的進程。優化AOF附加擁塞的問題主要是優化系統硬盤負載,優化方法見上壹節。
5.4多實例部署
Redis單線程架構,無法充分利用CPU的多核特性。通常的做法是在壹臺機器上部署多個Redis實例。當多個實例開始AOF重寫時,將會出現對CPU和IO的競爭。本節主要介紹針對該場景的分析和優化。上壹節介紹了與持久性相關的子進程開銷。對於單機多Redis部署,如果多個子進程同時運行,對當前系統的影響會非常明顯,因此需要采取壹種措施來隔離子進程。Redis為我們提供了監控info Persistence中子流程運行狀態的指標,如表5-2所示。
基於以上指標,我們可以通過外部程序輪詢來控制AOF重寫操作的執行,整個過程如圖5-6所示。
流程描述:
1)外部程序定期輪詢和監控機器上的所有Redis實例。
2)對於開始AOF的例子,檢查(AOF _當前_大小-AOF _基本_大小)/AOF _基本_大小以確認增長率。
3)當增長率超過壹定閾值(如100%)時,執行bgrewriteaof命令,手動觸發當前實例的aof重寫。
4)在運行期間定期檢查aof_rewrite_in_progress和aof_current_rewrite_time_sec的指示器,直到aof的重寫完成。
5)確認重寫實例AOF完成後,檢查其他實例並重復步驟2)~4)。從而保證機器中每個Redis實例AOF重寫串行化執行。
5.5本章重點復習。
1)Redis提供了兩種持久化方法:RDB和AOF。
2)RDB采用壹次生成內存快照的方式,文件緊湊,壓縮比更高,所以讀RDB的恢復速度更快。由於每次生成RDB開銷大,不能實時持久,壹般用於數據冷備和復制傳輸。
save命令會阻塞主線程,不建議這樣做。bgsave命令通過fork操作創建壹個子進程來生成RDB以避免阻塞。
4)AOF通過向文件追加寫命令來實現持久化,實時/秒的持久化可以通過appendfsync參數來控制。由於需要不斷追加寫命令,AOF文件的體積逐漸變大,需要定期進行重寫操作來減小文件體積。
5)AOF重寫可以通過auto-aof-rewrite-min-size和auto-aof-rewrite-percentage參數自動觸發,或者通過使用bgrewriteaof命令手動觸發。
6)子進程執行過程中,使用寫時復制機制與父進程* * *共享內存,避免內存消耗翻倍。在重寫AOF期間,還需要維護重寫緩沖區並保存新的寫命令,以避免數據丟失。
7)持久阻塞主線程場景包括:分叉阻塞和AOF附加阻塞。分支阻塞時間與內存量和系統有關。AOF的額外阻塞表明硬盤資源緊張。
8)在單臺機器上部署多個實例時,為了防止多個子進程進行重寫操作,建議做隔離控制,避免CPU和IO資源的競爭。