Redis持久化原理之RDB和AOF

Redis 有兩種持久化方案,RDB (Redis DataBase)和 AOF (Append Only File)。

RDB

      RDB 是 Redis 默認的持久化方案。在指定的時間間隔內(週期性),執行指定次數的寫操作,則會將內存中的數據寫入到磁盤中。即在指定目錄下生成一個dump.rdb文件。Redis 重啓會通過加載dump.rdb文件恢復數據。觸發RDB持久化過程分爲手動觸發和自動觸發。

相關的命令使用

      save命令: 阻塞當前Redis服務器, 直到RDB過程完成爲止, 對於內存比較大的實例會造成長時間阻塞, 線上環境不建議使用

      bgsave命令: Redis進程執行fork操作創建子進程, RDB持久化過程由子進程負責, 完成後自動結束。

壓縮

      Redis默認採用LZF算法對生成的RDB文件做壓縮處理, 壓縮後的文件遠遠小於內存大小, 默認開啓, 可以通過參數config set rdbcompression {yes|no}動態修改。雖然壓縮RDB會消耗CPU,但可大幅降低文件的體積,因此線上建議開啓。

優缺點     

   優點:
  • RDB是一個緊湊壓縮的二進制文件, 代表Redis在某個時間點上的數據快照。 非常適用於備份, 全量複製等場景。
  • Redis加載RDB恢復數據遠遠快於AOF的方式。
   缺點:
  • RDB方式數據沒辦法做到實時持久化/秒級持久化。 因爲bgsave每次運行都要執行fork操作創建子進程, 屬於重量級操作, 頻繁執行成本過高。
  • RDB文件使用特定二進制格式保存, Redis版本演進過程中有多個格式的RDB版本, 存在老版本Redis服務無法兼容新版RDB格式的問題。

AOF

    AOF(append only file) 持久化: 以獨立日誌的方式記錄每次寫命令,重啓時再重新執行AOF文件中的命令達到恢復數據的目的。 AOF的主要作用是解決了數據持久化的實時性, 目前已經是Redis持久化的主流方式。內容爲文本協議格式
    開啓AOF功能需要設置配置:appendonly yes,默認不開啓。AOF的默認文件名是appendonly.aof。

優缺點

    優點:AOF是一秒一去通過一個後臺的線程fsync操作,那最多丟這一秒的數據。AOF是以追加的方式寫數據,自然就少了很多磁盤尋址的開銷。
    缺點:一樣的數據AOF文件比RDB文件要大。

AOF的具體流程

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

    AOF緩衝區同步文件策略

  1. always---命令寫入aof_buf後調用系統fsync操作同步到AOF文件,fsync完成後線程使用。效率較低。不建議配置
  2. everysec---命令寫入aof_buf後調用系統write操作,write完成後線程返回。fsync同步文件操作由專門線程每秒調用一次。默認配置-兼顧性能和安全性,理論上只有在系統突然宕機的情況下丟失1秒的數據。
  3. no---命令寫入aof_buf後調用系統write操作,不對AOF文件做fsync同步,同步硬盤操作由操作系統負責,通常同步週期最常30秒。數據安全性無法保證

    AOF的write操作和fsync操作

  • write操作會觸發延遲寫(delayed write) 機制。 Linux在內核提供頁緩衝區用來提高硬盤IO性能。 write操作在寫入系統緩衝區後直接返回。 同步硬盤操作依賴於系統調度機制, 例如: 緩衝區頁空間寫滿或達到特定時間週期。同步文件之前, 如果此時系統故障宕機, 緩衝區內數據將丟失。
  • fsync針對單個文件操作(比如AOF文件) , 做強制硬盤同步, fsync將阻塞直到寫入硬盤完成後返回, 保證了數據持久化。

    AOF重寫機制

       AOF文件重寫是把Redis進程內的數據轉化爲寫命令同步到新AOF文件的過程。重寫後的AOF文件越來越小的原因如下:
  1. 進程內已經超時的數據不再寫入文件。
  2. 舊的AOF文件含有無效命令。
  3. 多條寫命令可以合併爲一個。

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資源的進程。

 

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