更多內容,歡迎關注微信公眾號:全菜工程師小輝~
Redis提供了將數據定期自動持久化至硬盤的能力,包括RDB和AOF兩種方案,兩種方案分別有其長處和短板,可以配合起來同時運行,確保數據的穩定性。
RDB
保存數據快照至一個RDB文件中,用於持久化。RDB操作和Mysql Dump相似。
執行方式
- save。同步操作,會阻塞Redis。
- bgsave。調用linux的fork(),然后使用新的線程執行復制。但是fork期間也會阻塞Redis,但是阻塞時間通常很短。
- 自動保存。Redis配置文件中設置了自動保存的觸發機制,可以自定義修改,運行原理同bgsave。
save和bgsave的對比
注意:
- 如果機器上運行多個Redis,需要配置RDB文件名稱,否則多個Redis的RDB文件會相互覆蓋。
除了上述三種執行方式,以下情況也會生成RDB文件:
- 主從的全量復制時,主機會生成RDB文件。
- Redis中的debug reload提供debug級別的重啟,不清空內存的一種重啟,這種方式也會觸發RDB文件的生成。
- 執行shutdown時,會觸發RDB文件的生成。
RDB的缺點
- 全量數據存儲,耗時。
- 雖然fork()采用copy-on-write策略,但仍消耗內存
- 寫RDB文件消耗大量IO性能。
AOF
采用AOF持久方式時,Redis會把每一個寫請求都記錄在一個日志文件里,AOF操作和Mysql Binlog相似。通過AOF重寫機制減少AOF文件的體積,從而減少恢復時間。
執行方式
- always。Redis的每條寫命令都寫入到系統緩沖區,然后每條寫命令都使用fsync“寫入”硬盤。
- everysec。過程與always相同,只是fsync的頻率為1秒鍾一次。這個是Redis默認配置,如果系統宕機,會丟失一秒左右的數據
- no。由操作系統決定什么時候從系統緩沖區刷新到硬盤。
AOF重寫
為了解決AOF文件體積膨脹的問題,Redis提供了AOF重寫功能:Redis服務器可以創建一個新的AOF文件來替代現有的AOF文件,新舊兩個文件所保存的數據庫狀態是相同的,但是新的AOF文件不會包含任何浪費空間的冗余命令,通常體積會較舊AOF文件小很多。
AOF重寫方式
- bgrewriteaof(流程與bgsave相似)
- AOF重寫配置(與RDB自動保存相似)
AOF重寫並不需要對原有AOF文件進行任何的讀取,寫入,分析等操作,這個功能是通過讀取服務器當前的數據庫狀態來實現的。
RDB vs AOF
Redis啟動時的數據加載
Redis啟動數據加載流程:
- AOF持久化開啟且存在AOF文件時,優先加載AOF文件。
- AOF關閉或者AOF文件不存在時,加載RDB文件。
- 加載AOF/RDB文件成功后,Redis啟動成功。
- AOF/RDB文件存在錯誤時,Redis啟動失敗並打印錯誤信息。
開發運維中常見的問題
fork操作
fork()的實際開銷就是復制父進程的頁表以及給子進程創建一個進程描述符,所以速度一般比較快
內存量越大,耗時越長;物理機相對較快,虛擬機相對較慢。
優化方法
- 優先使用物理機或者高效支持fork操作的虛擬化技術
- 控制Redis實例最大可用內存maxmemory
- 合理配置Linux內存分配策略:vm.overcommit_memory=1。默認值為0,會使Linux在內存分配時,發現不夠內存不足時,不會進行分配,進而造成fork阻塞
- 降低fork頻率。例如放寬AOF重寫自動觸發時機或者減少不必要的主從全量復制
進程外開銷
- CPU。RDB和AOF文件生成,屬於CPU密集型。不要將Redis進程綁定在某個CPU上,防止單核過載;同時Redis不和CPU密集型應用一起部署。
- 內存。fork內存開銷,copy-on-write。
- 硬盤。AOF和RDB文件的寫入。可以結合iostat和iotop進行分析。
優化方法
- 不要和高硬盤負載服務部署在一起:存儲服務、消息隊列等
- 配置no-appendfsync-on-rewrite=yes。這樣在AOF重寫的期間,不要進行AOF追加操作(主線程只將數據寫入緩沖區),可以減少內存的開銷。
但如果AOF重寫期間,Redis宕機的話,在Linux的系統默認配置下,最多會丟失30s的數據。如果無法忍受數據丟失,no-appendfsync-on-rewrite配置no;如果應用系統無法忍受延遲,而可以容忍少量的數據丟失,則設置為yes。
- 根據寫入量決定磁盤類型:例如ssd
- 單機多實例持久化文件目錄可以考慮分盤,或者使用類似cgroups機制進行硬盤資源的合理分配
AOF追加阻塞
例如在AOF的everysec策略中,主線程會對比上次fsync的時間,如果距離上次fsync時間超過兩秒,就會造成主線程阻塞(等待同步線程同步完成)。
日常開發可以使用info persistence
命令,查看歷史發生AOF阻塞的次數;然而需要了解AOF追加阻塞的發生時間則需要查看Redis日志。
發送AOF追加阻塞的時候,日志如下:
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.
優化方法(參考其他方面的優化點)
更多內容,歡迎關注微信公眾號:全菜工程師小輝~