1. 程式人生 > >Redis-AOF持久化

Redis-AOF持久化

Redis持久化-AOF

一. AOF持久化原理

 AOF(append only file)持久化是以獨立日誌的方式記錄每次寫命令,重啟時再重新執行AOF檔案中的命令達到恢復資料的目的。AOF主要作用是解決了資料持久化的實時性,目前已經是redis持久化的主流方式。

二. 開啟AOF持久化

(1)開啟AOF持久化,需要設定appendonly引數的值為yes,預設不開啟。

(2)aof檔名通過appendfilename配置設定,預設檔名為appendonly.aof

(3)aof檔案儲存路徑通過dir引數來指定。

redis.conf中的相關配置如下:

appendonly yes(此處需修改為yes,啟用aof,預設為no)

appendfilename "appendonly.aof"

dir "/home/devuser/software/redis/redis-3.2.4/redis_instance/8001"

三 AOF的工作流程

3.1 工作流程

(1)      所有寫命令會被追加aof_buf(緩衝區)中

(2)      AOF緩衝區根據對應的策略向硬碟做同步操作

(3)      隨著AOF檔案越來越大,需要定期對AOF檔案進行重寫,達到壓縮的目的

(4)      當 redis伺服器進行重啟時,可以加在AOF檔案進行資料恢復

3.2 命令寫入

(1)AOF命令寫入的內容直接是文字協議格式,因為該協議具有很好的相容性,可讀性,方便直接修改和處理。開啟AOF後,所有寫入命令都包含追加操作,直接採用協議格式避免了二次處理的開銷。

(2)命令寫入只是將命令追加到AOF緩衝區中,因為redis是採用單執行緒響應命令,如果每次寫AOF命令都直接追加到硬碟,那麼效能完全取決於當前硬碟的負載。先寫入AOF緩衝區中還有另一個好處,redis可以提供多種緩衝區同步硬碟的策略,在效能和安全性方面作曲權衡。

3.3 檔案同步

3.3.1 AOF緩衝區同步檔案策略

Redis提供了多種AOF緩衝區同步檔案策略,由引數appendfsync控制。

apendfsync引數的選項如下:

always:命令寫入AOF緩衝區後呼叫系統fsync操作同步到AOF檔案中,fsync完成後執行緒返回

everysec(預設配置):命令寫入AOF緩衝區後呼叫系統write操作,write完成後執行緒返回。fsync同步檔案操作由專門執行緒每秒呼叫一次。Everysec是建議的同步策略。理論上只有在系統突然宕機的情況下丟失1秒的資料。

no:命令寫入AOF緩衝區後呼叫系統write操作,write完成後執行緒後執行緒返回,不對AOF檔案作fsync同步,同步硬碟操作由作業系統負責,通常同步週期最長30秒。

3.3.2 系統呼叫write和fsync說明

(1)write

Wirte操作會觸發延遲寫機制。在寫入系統緩衝區後直接返回,同步硬碟操作依賴於系統排程機制。同步硬碟之前,如果系統故障宕機,緩衝區內的資料將丟失。

(2)fsync

Fsync針對單個檔案操作(比如AOF檔案),做強制硬碟同步,fsync將阻塞直到寫入硬碟完成後返回,保證了資料持久化。

3.4 檔案重寫

3.4.1 AOF檔案重寫的作用

隨著命令的不斷寫入,AOF檔案越來越大。AOF檔案重寫是把Redis程序內的資料轉化為寫命令同步到新AOF檔案的過程。更小的AOF檔案降低了檔案佔用空間,也可以更快的被redis載入。

3.4.2 AOF檔案重寫後變小的原因

1)  程序內已經超時的資料不再寫入檔案

2)  舊的AOF檔案中含有無效的命令,如seta111,重寫使用程序內資料直接生成,這樣新的AOF檔案只保留最終資料寫入命令。

3)  多條寫命令可以合併為1個,如:lpushlist a、lpush list b可以合併為lpush list a b,為防止單條命令過大造成客戶端緩衝區溢位,對於list,set,zset,hash等操作,以64個元素為界拆分為多條。

3.4.3 AOF重寫觸發方式
3.4.3.1 手動觸發

直接呼叫bgrewriteaof命令

3.4.3.2 自動觸發

根據auto-aof-rewrite-min-size和auto-aof-rewrite-percentage引數確定自動觸發時機。

auto-aof-rewrite-min-size:表示執行AOF重寫時aof檔案的最小體積。預設為64MB。

auto-aof-rewrite-percentage:代表當前AOF檔案空間(aof_current_size)和上一次重寫後AOF檔案空間(aof_base_size)的比值

自動觸發時機=aof_current_size>auto-aof-rewrite-min-size&&(aof_current_size-aof_base_size)/aof_base_size>=auto-aof-rewrite-percentage

Reids.conf中的預設設定:

auto-aof-rewrite-percentage 100

auto-aof-rewrite-min-size 64mb

aof_current_size和aof_base_size可以通過infopersistence

10.3.34.101:6378> info persistence

# Persistence

loading:0

rdb_changes_since_last_save:3

rdb_bgsave_in_progress:0

rdb_last_save_time:1500430990

rdb_last_bgsave_status:ok

rdb_last_bgsave_time_sec:0

rdb_current_bgsave_time_sec:-1

aof_enabled:1

aof_rewrite_in_progress:0

aof_rewrite_scheduled:0

aof_last_rewrite_time_sec:0

aof_current_rewrite_time_sec:-1

aof_last_bgrewrite_status:ok

aof_last_write_status:ok

aof_current_size:924

aof_base_size:817

aof_pending_rewrite:0

aof_buffer_length:0

aof_rewrite_buffer_length:0

aof_pending_bio_fsync:0

aof_delayed_fsync:0

3.4.4 AOF重寫工作流程

(1)      執行AOF重寫請求

a.      如果當前程序正在執行AOF重寫,當前請求不執行,並返回如下響應:

ErrorBackground append only file rewriting already in progress

b.      如果當前程序正在執行bgsave操作,重寫命令延遲到bgsave操作結束後再執行,並返回如下響應:

Background append only file rewriting scheduled

(2)      父程序執行fork操作建立子程序,fork操作執行過程中,redis父程序會阻塞。

(3)      主程序fork操作完成後,繼續響應其他命令。所有修改命令繼續寫入AOF緩衝區(AOF_BUF)並根據appendfsync策略同步到硬碟,保證原有AOF機制的正確性。

(4)      由於fork操作運用寫時複製技術,子程序只能共享fork操作時的記憶體資料。由於父程序依然響應命令,Redis使用“AOF重寫緩衝區”儲存這部分資料,防止新AOF檔案生成期間丟失這部分資料。

(5)      子程序根據記憶體快照,按照命令合併規則寫入到新的AOF檔案。每次批量寫入硬碟數量由配置aof-rewrite-incremental-fsync控制,預設為32MB,防止單次刷盤資料過多造成阻塞。

(6)      新AOF檔案寫入完成後,子程序傳送訊號給父程序,父程序更新統計資訊

(7)      父程序將AOF重寫緩衝區的資料寫入到新的AOF檔案

(8)      使用新的AOF檔案替換老檔案,完成AOF重寫。

3.5 重啟載入

AOF和RDB都可以用於伺服器重啟時的資料恢復。下圖表示Redis持久化檔案的載入流程。

流程說明:
1.AOF持久化開啟且存在AOF檔案時,優先載入AOF檔案,列印如下日誌:
*DB loaded from append only file: 5.841 seconds
2.AOF關閉或者AOF檔案不存在時,載入RDB檔案,列印如下日誌:
   * DB loaded from disk:5.586seconds
3. 載入AOF/RDB檔案存在錯誤,Redis啟動失敗並列印錯誤資訊


3.6 檔案校驗

載入損壞的AOF檔案時會拒絕啟動,並列印如下日誌:

# Bad file format reading the append onlyfile:make a backup of your AOF file.then user ./redis-check-aof–fix<filename>

對於錯誤格式的AOF檔案,先進行備份,然後採用redis-check-aof–fix命令進行修復,修復後使用diff –u對比資料差異,找出丟失的資料,有些可以人工修改補全。

AOF檔案可能存在結尾不完整的情況,比如機器突然掉電導致AOF尾部檔案命令寫入不全。Redis為我們提供了aof-load-truncated配置來相容這種情況,預設開啟。載入AOF時,當遇到此問題時會忽略並繼續啟動,同時列印如下警告日誌;

#!!! Warningshort read while looading the AOF file !!!

#!!! Truncatingthe AOF at offset 397856725 !!!

#!!! AOF loadedanyway because aof-load-truncated is enabled

四, 問題定位與優化

4.1 fork操作

Fork操作會阻塞redis程序,對於高流量的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失敗。

(4)      降低fork操作的頻率,如適度放寬AOF自動觸發時機,避免不必要的全量複製等。

4.2 子程序開銷監控和優化

4.2.1 CPU

Redis屬於CPU密集型操作,通常子程序對單核CPU利用率接近90%。

(1)      不要繫結單核CPU操作。由於子程序非常消耗CPU,會和父程序產生單核資源競爭。

(2)      不要和其他CPU密集型服務部署在一起,造成CPU過渡競爭

(3)      如果部署多個REDIS例項,儘量保證同一時間只有一個子程序執行重寫工作。

4.2.2 記憶體

子程序通過fork操作產生,佔用記憶體大小等同於父程序,理論上需要兩倍記憶體來完成持久化操作,但Linux有寫時複製機制。父子程序會共享相同的實體記憶體頁,當父程序處理寫請求時會把要修改的頁建立副本,而子程序在fork操作過程中共享整個父程序記憶體快照。

(1)      如果部署多個Redis例項,儘量保證同一時刻只有一個子程序在工作。

(2)      避免大量寫入時做子程序重寫操作,這樣將導致父程序維護大量頁副本,造成記憶體消耗

(3)      Linux kernel在2.6.38核心增加了TransarentHuge Pages(THP)。支援huge page(2MB)的頁分配,預設開啟。當開啟時可以降低fork建立子程序的速度,但執行fork後,如果開啟THP,複製單位從原來的4KB變為2MB,會大幅增加重寫期間父程序記憶體消耗,建議設定“sudo echo never>/sys/kernel/mm/transparent_hugepage/enabled“,關閉THP。

4.2.3 硬碟

子程序主要職責是將AOF或者RDB檔案寫入磁碟持久化。勢必造成硬碟寫入壓力。根據Redis重寫AOF/RDB的資料量,結合系統工具如sar、iostat、iotop等,可分析出重寫期間硬碟負載情況。

硬碟開銷優化方法:

(1)      不要和其他高硬碟負載的服務部署在一起,如:儲存服務、訊息佇列服務等

(2)      AOF重寫時會消耗大量硬碟IO,可以開啟配置no-appendfsync-on-rewrtie,預設關閉。表示在AOF重寫期間不做fsync操作。如果配置,有可能丟失整個AOF重寫期間的資料,需要根據資料安全性決定是否配置。

(3)      當開啟AOF功能的redis用於高流量寫入場景時,如果使用普通機械磁碟,寫入吞吐一般在100MB/S左右,這時Redis例項的瓶頸主要在AOF同步硬碟上。

(4)      對於單機配置多個Redis例項的情況,可以配置不同例項分盤儲存AOF檔案,分攤磁碟寫入壓力

4.3 AOF追加阻塞


阻塞流程分析:

(1)      主執行緒負責寫入AOF緩衝區

(2)      AOF執行緒負責每秒執行一次同步磁碟操作,並記錄最近一次同步時間

(3)      主執行緒負責對比上次AOF同步時間

a.      如果距上次同步成功時間在2秒內,主執行緒直接返回。

b.      如果距上次同步成功時間超過2秒,主執行緒將會阻塞,直到同步操作完成。

通過對AOF阻塞流程可以發現兩個問題:

a.      everysec配置最多可能丟失2秒資料,不是1秒

b.      如果系統fsync緩慢,將會導致Redis主執行緒阻塞影響效率

    AOF阻塞問題定位:

(1)      發生AOF阻塞時,Redis輸出如下日誌,:

Asynchronous AOF fsync is taking toolong(disk is busy). Wrting the AOF buffer without waiting for fsync tocomplete,this may slow down Redis

(2)      每當發生AOF追加阻塞事件發生時,在info persistence統計中,aof_delayed_fsync指標會累加,檢視這個指標方便定位AOF阻塞問題

AOF同步最多允許2秒的延遲,當延遲發生時,說明硬碟存在高負責問題,可以通過監控工具如iotop,定位消耗硬碟IO資源的程序。