Redis持久化整理

1 介紹

Redis支持RDB和AOF兩種持久化機制,持久化有效避免因進程退出數據丟失問題,重啓時利用之前持久化的文件即可實現數
據恢復。

2 RDB

RDB持久化把當前進程數據生成快照保存到硬盤,代表Redis在某個時間點上的數據快照,RDB有手動和自動觸發。
- 手動觸發
- save:阻塞服務器,直到RDB完成,已棄用
- bgsave:Redis進程fork出子進程,RDB持久化過程由子進程負責,完成後自動結束。Redis內部的RDB都採用bgsave。
- 自動觸發
內部自動觸發RDB持久化有:①save m n配置(m秒內存在n次修改,自動觸發bgsave);②從節點執行全量複製,主節點自動執行bgsave,生成文件發往從節點;③debug reload自動觸發’save’;④默認下shutdown,若沒開啓AOF,自動執行bgsave

2.1 bgsave是主流的觸發RDB持久化方式

流程如下:
bgsave->父進程->fork->子進程->生成RDB文件->父進程

  1. 執行bgsave,Redis父進程判斷是否有正在執行的子進程(eg.RDB/AOF子進程),存在則直接返回;
  2. 父進程fork創建子進程,fork過程中父進程會阻塞(info stats查看latest_fork_usec,最近一個fork操作耗時-微秒);
  3. fork完成後,bgsave返回“Background saving started”,不再阻塞父進程,可繼續響應其他命令;
  4. 子進程創建RDB文件,根據父進程內存 生成 臨時快照文件,完成後對原有文件進行原子替換(lastsave的rdb_last_save_time,最後一次生成RDB的時間);
  5. 信號通知父進程,以更新統計信息。

配置文件的dir:RDB文件保存目錄,dbfilename:其文件名。

壞盤或磁盤寫滿時,在線修改config set dir{newDir}到新的可用磁盤路徑,然後bgsave磁盤切換(RDB、AOF都適用)。
同理,可在線config set dbfilename{newFileName}。
Redis默認採用LZF算法壓縮RDB文件,遠遠小於內存數據,消耗CPU但大幅↓文件體積,方便保存或網絡傳輸,線上建議開啓(默認開)。(config set rdbcompression{yes|no})

2.2 優缺點

優: ①緊湊壓縮的二進制文件,可每X小時執行bgsave備份,災難恢復;②加載RDB恢復數據遠遠快於AOF。
缺: ①無法實時持久化(bgsave每次都要fork建子進程,重量級操作);②特定二進制格式,新舊版不兼容。

3 AOF

AOF(append only file)持久化,日誌 記錄每次寫命令,重啓時再重新執行AOF文件中的命令,恢復數據。它解決了數據持久化的實時性。理解掌握好其機制,↑兼顧數據安全性和性能。

開啓AOF:appendonly yes(默認不開啓)
AOF文件名:appendfilename(默認文件名appendonly.aof)
保存路徑:dir(同RDB)

3.1 AOF是Redis持久化的主流方式

AOF工作流程:
命令寫入(append)->AOF緩衝->文件同步(sync)->AOF文件->文件重寫(rewrite)<-重啓加載(load)


  1. 所有的寫入命令會追加到aof_buf(緩衝區);
  2. AOF緩衝區根據對應的策略向硬盤做同步操作;
  3. 隨着AOF文件越來越大,需定期對AOF文件進行重寫,達到壓縮目的;
  4. 當Redis服務器重啓時,可加載AOF文件進行數據恢復。
    • 命令寫入
      AOF直接採用文本協議格式

①文本協議兼容性很好;②開啓AOF後,所有寫入命令都包含追加操作,直接採用協議格式,避免了二次處理開銷;③可讀性,方便直接修改和處理。
AOF爲何把命令追加到aof_buf(緩衝區)?
①Redis單線程響應命令,直接追加到硬盤,性能完全取決於當前硬盤負載;②可提供多種緩衝區同步硬盤的策略,在性能和安全性做平衡。
- 文件同步
Redis提供了多種AOF緩衝區同步文件策略,由參數appendfsync控制。
always:不建議配置。每次寫入都要同步,代價高;
no:性能↑,但數據安全性無法保證;
everysec: 建議配置,默認配置。兼顧性能和數據安全性。理論上系統突然宕機會丟失1秒數據。
- 重寫機制
隨着命令不斷寫入,AOF文件越來越大,重寫機制可壓縮文件體積。重寫把進程內數據->寫命令,同步->新AOF文件。

重寫後體積變小,可更快被Redis加載

①已超時不寫入;②新AOF文件只保留最終數據的寫入命令;③多條寫命令合併爲一個(eg.lpush list a、lpush list b…->lpush list a b …),防客戶端緩衝區溢出。

手動觸發:bgrewriteaof
自動觸發:auto-aof-rewrite-min-size、auto-aof-rewrite-percentage

bgrewriteaof->父進程->fork->(aof_buf->舊AOF文件,aof_rewrite_buf->新AOF文件子進程->信號通知父進程->新AOF文件

1.執行AOF重寫請求,若正在執行bgsave,重寫命令延遲到bgsave完成之後;
2.父進程fork子進程;
3.1 fork後,繼續響應,寫入AOF緩衝區+appendfsync策略同步硬盤,保證正確性; 3.2 fork(寫時複製技術),子進程只能共享fork操作時的內存數據。用AOF重寫緩衝區保存新數據;
4.子進程根據內存快照,按照命令合併規則寫入新AOF文件;
5.1寫到新文件後,通知父進程;
5.2父進程把AOF重寫緩衝區的數據寫入到新AOF文件;
5.3替換老文件,完成重寫。
- 重啓加載
持久化文件加載流程:

1.AOF持久化開啓且存在AOF文件時,優先加載AOF文件;2.AOF關閉或者AOF文件不存在時,加載RDB文件; 3. 加載成功後,Redis啓動否則打印失敗日誌。
- 文件校驗
加載損壞的AOF文件時會拒絕啓動。此時,先備份,然後後redis-check-aof--fix修復,最後diff-u對比差異,人工修改補全(不完整)。當突然掉電,AOF尾部不全時,aof-load-truncated(默認開啓)可忽略並繼續啓動redis。

3.2 問題定位優化


  • fork

fork會複製父進程的空間內存頁表,eg.10GB的Redis,需複製約20MB內存頁表,fork耗時跟進程總內存量成正比。
改善:

①優先物理機;②控制Redis實例最大可用內存(單實例10G以內);③合理配置Linux內存分配策略;④降低fork頻率,↓全量複製。
  • 子進程開銷
    子進程負責AOF|RDB文件的重寫,主要涉及CPU、內存、硬盤消耗。
    CPU:
    多個redis實例,保證同一時刻只有一個子進程重寫。因爲redis本身是CPU密集型服務,子進程又負責進程內數據分批寫入文件,非常消耗CPU,單核CPU會和父進程產生資源競爭。
    內存:
    多個Redis實例儘量保證同一時刻只有一個子進程在工作;大量寫入時避免子進程重寫操作。
    硬盤:
    不部署在高負載的硬盤;AOF重寫期間不做fsync操作(默認關閉)。
  • AOF追加阻塞
    主線程->AOF緩衝區->同步線程->同步磁盤,AOF緩衝區->對比上次fsync時間->小於2秒通過,大於2秒阻塞
    優化AOF追加阻塞問題主要是優化系統硬盤負載。
  • 總結

    生成RDB開銷較大,一般用於數據冷備和複製傳輸;
    AOF文件體積逐漸變大,定期執行重寫操作降低文件體積;
    AOF重寫:auto-aof-rewrite-min-size,auto-aofrewritepercentage參數自動觸發,bgrewriteaof手動觸發;
    子進程執行期間,copy-on-write與父進程共享內存,防內存消耗翻倍。AOF重寫期間,維護重寫緩衝區,保存新的寫入命令避免數據丟失;
    持久化阻塞主線程:fork阻塞時間跟內存量和系統有關,AOF追加阻塞說明硬盤資源緊張;
    單機多實例,防多個子進程重寫,做隔離控制。

    參考:
    《redis開發與運維》

    發表評論
    所有評論
    還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
    相關文章