1. 程式人生 > 實用技巧 >Liunx之編譯指令碼Makefile三層

Liunx之編譯指令碼Makefile三層

AOF( append only file) 持久化

以獨立日誌的方式記錄每次寫命令,重啟時再重新執行AOF檔案中的命令達到恢復資料的目的。 AOF的主要作用是解決了資料持久化的實時性, 目前已經是Redis持久化的主流方式。 理解掌握好AOF持久化機制對我們兼顧資料安全性和效能非常有幫助。

AOF配置

開啟AOF功能需要設定配置: appendonly yes, 預設不開啟。

AOF檔名通過appendfilename配置設定,預設檔名是appendonly.aof。 儲存路徑同RDB持久化方式一致,通過dir配置指定。

AOF運作流程

1) 所有的寫入命令會追加到aof_buf( 緩衝區)中。
2) AOF緩衝區根據對應的策略向硬碟做同步操作。 3) 隨著AOF檔案越來越大,需要定期對AOF檔案進行重寫,達到壓縮的目的。 4) 當Redis伺服器重啟時,可以載入AOF檔案進行資料恢復。

寫入命令

AOF命令寫入的內容直接是文字協議格式。 例如set hello world這條命令, 在AOF緩衝區會追加如下文字:

*3\r\n$3\r\nset\r\n$5\r\nhello\r\n$5\r\nworld\r\n

AOF為什麼直接採用文字協議格式?

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

AOF為什麼把命令追加到aof_buf中?

Redis使用單執行緒響應命令,如果每次寫AOF檔案命令都直接追加到硬碟,那麼效能完全取決於當前硬碟負載。 
先寫入緩衝區aof_buf中,還有另一個好處,Redis可以提供多種緩衝區同步硬碟的策略,在效能和安全性方面做出平衡。

檔案同步

Redis提供了多種AOF緩衝區同步檔案策略,由引數appendfsync控制,不同值的含義如下:

always    命令寫入aof_buf後,呼叫系統fsync操作同步到AOF文,fsync完成後執行緒返回
everysec  命令寫入aof_buf後呼叫系統write操作,write完成後執行緒返回。fsync同步檔案操作由專門執行緒每秒呼叫一次
no        命令下入aof_buf後呼叫系統write操作,不對AOF檔案做fsync同步,同步硬碟操作由作業系統負責,通常同步週期最長30秒

系統呼叫write和fsync說明

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

引數解說

·配置為always時, 每次寫入都要同步AOF檔案, 在一般的SATA硬碟上, Redis只能支援大約幾百TPS寫入, 顯然跟Redis高效能特性背道而馳,不建議配置。
·配置為no, 由於作業系統每次同步AOF檔案的週期不可控, 而且會加大每次同步硬碟的資料量, 雖然提升了效能, 但資料安全性無法保證。
·配置為everysec, 是建議的同步策略, 也是預設配置, 做到兼顧效能和資料安全性。 理論上只有在系統突然宕機的情況下丟失1秒的資料。

重寫機制

隨著命令不斷寫入AOF,檔案會越來越大,為了解決這個問題,Redis引入AOF重寫機制壓縮檔案體積。

AOF檔案重寫是把Redis程序內的資料轉化為寫命令同步到新AOF檔案的過程。

為什麼要重寫?

AOF重寫降低了檔案佔用空間。
更小的AOF檔案可以更快地被Redis載入。

重寫後的AOF檔案為什麼可以變小?

1) 程序內已經超時的資料不再寫入檔案。
2) 舊的AOF檔案含有無效命令, 如del key1、 hdel key2、 srem keys、 seta111、 set a222等。 重寫使用程序內資料直接生成, 這樣新的AOF檔案只保留最終資料的寫入命令。
3) 多條寫命令可以合併為一個, 如: lpush list a、 lpush list b、 lpush list c可以轉化為: lpush list a b c。 為了防止單條命令過大造成客戶端緩衝區溢位, 對於list、 set、 hash、 zset等型別操作, 以64個元素為界拆分為多條。


重寫的觸發
手動觸發

直接呼叫bgrewriteaof命令

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

·auto-aof-rewrite-min-size: 表示執行AOF重寫時檔案最小體積, 預設為64MB。
·auto-aof-rewrite-percentage: 代表當前AOF檔案空間( aof_current_size) 和上一次重寫後AOF檔案空間( aof_base_size) 的比值。

自動觸發時機=aof_current_size>auto-aof-rewrite-minsize&&( aof_current_size-aof_base_size) /aof_base_size>=auto-aof-rewritepercentage

其中aof_current_size和aof_base_size可以在info Persistence統計資訊中檢視。

AOF重寫運作流程

1) 執行AOF重寫請求。

如果當前程序正在執行AOF重寫, 請求不執行並返回如下響應:
  ERR Background append only file rewriting already in progress
如果當前程序正在執行bgsave操作, 重寫命令延遲到bgsave完成之後再執行, 返回如下響應:
  Background append only file rewriting scheduled

2) 父程序執行fork建立子程序,開銷等同於bgsave過程。

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

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

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

5.1)新AOF檔案寫入完成後, 子程序傳送訊號給父程序, 父程序更新統計資訊, 具體見info persistence下的aof_*相關統計。

5.2)父程序把AOF重寫緩衝區的資料寫入到新的AOF檔案。

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

重啟載入

redis持久化載入流程:

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

檔案校驗

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

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

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

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

# !!! Warning: short read while loading the AOF file !!!
# !!! Truncating the AOF at offset 397856725 !!!
# AOF loaded anyway because aof-load-truncated is enabled