天天看點

Redis 分享-AOF的阻塞簡單記錄AOF

背景

團隊内每周延安大學分享中,redis中讨論了一個AOF會阻塞主線程的問題,這個問題之前沒考慮到過,一直以為fork了子程序一定不會阻塞,沒有深度考慮。

因為大家也沒有深入研究,這裡整理一下,因為這塊确實實踐較少,可能有描述不準确的,大家多多提意見指正,我多多完善。

AOF

redis中文官網:

http://www.redis.cn/topics/persistence.html

什麼是AOF

以下定義均來自中文官網

隻追加操作的檔案(Append-only file,AOF)

快照功能(RDB)并不是非常耐久(dura ble): 如果 Redis 因為某些原因而造成故障停機, 那麼伺服器将丢失最近寫入、且仍未儲存到快照中的那些資料。 從 1.1 版本開始, Redis 增加了一種完全耐久的持久化方式: AOF 持久化。

你可以在配置檔案中打開AOF方式:

appendonly yes

從現在開始, 每當 Redis 執行一個改變資料集的指令時(比如 SET), 這個指令就會被追加到 AOF 檔案的末尾。這樣的話, 當 Redis 重新啟時, 程式就可以通過重新執行 AOF 檔案中的指令來達到重建資料集的目的。

日志重寫

因為 AOF 的運作方式是不斷地将指令追加到檔案的末尾, 是以随着寫入指令的不斷增加, AOF 檔案的體積也會變得越來越大。舉個例子, 如果你對一個計數器調用了 100 次 INCR , 那麼僅僅是為了儲存這個計數器的目前值, AOF 檔案就需要使用 100 條記錄(entry)。然而在實際上, 隻使用一條 SET 指令已經足以儲存計數器的目前值了, 其餘 99 條記錄實際上都是多餘的。

為了處理這種情況, Redis 支援一種有趣的特性: 可以在不打斷服務用戶端的情況下, 對 AOF 檔案進行重建(rebuild)。執行 BGREWRITEAOF 指令, Redis 将生成一個新的 AOF 檔案, 這個檔案包含重建目前資料集所需的最少指令。

Redis 2.2 需要自己手動執行 BGREWRITEAOF 指令; Redis 2.4 則可以自動觸發 AOF 重寫, 具體資訊請檢視 2.4 的示例配置檔案。

通過官網基本可以了解了什麼是AOF和重寫,如果可以想了解AOF和RDB的差別,官網也有描述可以通過上面連結去閱讀。

rdb:預設開啟,檔案小,格式緊湊,資料恢複快,比較适合用來做災備,服務當機丢資料更多一些

aof:預設關閉,檔案大,資料恢複慢,但是資料更加完整,支援多種同步政策。

官方推薦使用混合模式。

AOF寫入政策

由appendfsync參數控制:

可配置的值 說明
always 指令寫入buf後調用系統調用fsync同步AOF檔案,fsync完成後線程傳回。
no 指令寫入buf後調用系統調用write操作,後續fsync同步操作由作業系統來完成,一般為30秒一次。
everysec 指令寫入buf後調用系統調用write操作,後續fsync同步操作專門線程每一秒調用一次。

everysec是always和no的折中,是性能和安全性的這種,是redis預設的配置,也是比較推薦的配置。

重寫流程圖

重寫流程:
  1. bgrewriteaof 觸發重寫,判斷是否目前有bgsave或bgrewriteaof在運作,如果有,則等待該指令結束後再繼續執行
  2. 主程序fork出子程序執行重寫操作,保證主程序不會阻塞
  3. 子程序周遊redis記憶體中資料到臨時檔案,用戶端的寫請求同時寫入aof_buf緩沖區和aof_rewrite_buf重寫緩沖區 保證原AOF檔案完整以及新AOF檔案生成期間的新的資料修改動作不會丢失
  4. 1).子程序寫完新的AOF檔案後,向主程序發信号,父程序更新統計資訊。2).主程序把aof_rewrite_buf中的資料寫入到新的AOF檔案
  5. 使用新的AOF檔案覆寫舊的AOF檔案,完成AOF重寫

流程圖來源:

https://blog.csdn.net/wsdc0521/article/details/106765809

阻塞

雖然在everysec配置下aof的fsync是由子線程進行操作的,但是主線程會監控fsync的執行進度。

主線程在執行時候如果發現上一次的fsync操作還沒有傳回(也有一種對比上一次的fsync操作時間,大于2秒阻塞的),那麼主線程就會阻塞。

解決阻塞

  1. 修改配置為yes,減少IO競争:

no-appendfsync-on-rewrite yes/no

    • 設定為yes,重寫期間會停止

      appendfsync

      操作,避免io競争((表示在日志重寫時,不進行指令追加操作,而隻是将指令放在重寫緩沖區裡,避免與指令的追加造成磁盤

      IO

      上的沖突))。但是這樣的風險:如果在aof重寫期間redis當機了,那麼aof的資料便會丢失,可靠性下降。
    • 配置就是設定為no時候,aof重寫期間還是會執行

      fsync

      ,這個時候就會産生IO競争,有可能阻塞主線程。如果目前AOF檔案很大,那麼相應的rewrite時間會變長,

      appendfsync

      被阻塞的時間也會更長
  1. 為了保證可靠性,進行叢集化
    • 給目前Redis執行個體添加slave節點,目前節點設定為master, 然後master節點關閉AOF,slave節點開啟AOF。
    • 這樣的方式的風險是如果master挂掉,尚沒有同步到salve的資料會丢失。而且 叢集選舉時,aof配置怎麼根據選舉結果動态修改修改,可能需要手動上去改一遍。感覺運維成本比較大。
  1. 閑的時間定時重寫、提升伺服器io性能
    1. 在淩晨低峰期定時手動執行

      bgrewriteaof

      指令完成每日一次的

      AOF

      重寫
    2. 比如使用ssd
      1. 将配置設為no
      2. 硬碟采用高速固态硬碟SSD
    1. 如果是三方伺服器,購買私有或者使用者隔離的混合雲,不要購買共有雲,不要讓其他使用者影響該伺服器磁盤穩定性
  1. 上監控人工介入,監控所有系統必不可少的一部分。
    1. 在重寫時為了避免硬碟空間不足或者

      IO

      使用率高影響重寫功能,我們還添加了硬碟空間報警和

      IO

      使用率報警保

擴充連結

繼續閱讀