背景
團隊内每周延安大學分享中,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預設的配置,也是比較推薦的配置。
重寫流程圖
重寫流程:
- bgrewriteaof 觸發重寫,判斷是否目前有bgsave或bgrewriteaof在運作,如果有,則等待該指令結束後再繼續執行
- 主程序fork出子程序執行重寫操作,保證主程序不會阻塞
- 子程序周遊redis記憶體中資料到臨時檔案,用戶端的寫請求同時寫入aof_buf緩沖區和aof_rewrite_buf重寫緩沖區 保證原AOF檔案完整以及新AOF檔案生成期間的新的資料修改動作不會丢失
- 1).子程序寫完新的AOF檔案後,向主程序發信号,父程序更新統計資訊。2).主程序把aof_rewrite_buf中的資料寫入到新的AOF檔案
- 使用新的AOF檔案覆寫舊的AOF檔案,完成AOF重寫
流程圖來源:
https://blog.csdn.net/wsdc0521/article/details/106765809阻塞
雖然在everysec配置下aof的fsync是由子線程進行操作的,但是主線程會監控fsync的執行進度。
主線程在執行時候如果發現上一次的fsync操作還沒有傳回(也有一種對比上一次的fsync操作時間,大于2秒阻塞的),那麼主線程就會阻塞。
解決阻塞
- 修改配置為yes,減少IO競争:
no-appendfsync-on-rewrite yes/no
-
- 設定為yes,重寫期間會停止
操作,避免io競争((表示在日志重寫時,不進行指令追加操作,而隻是将指令放在重寫緩沖區裡,避免與指令的追加造成磁盤appendfsync
上的沖突))。但是這樣的風險:如果在aof重寫期間redis當機了,那麼aof的資料便會丢失,可靠性下降。IO
- 配置就是設定為no時候,aof重寫期間還是會執行
,這個時候就會産生IO競争,有可能阻塞主線程。如果目前AOF檔案很大,那麼相應的rewrite時間會變長,fsync
被阻塞的時間也會更長appendfsync
- 設定為yes,重寫期間會停止
- 為了保證可靠性,進行叢集化
-
- 給目前Redis執行個體添加slave節點,目前節點設定為master, 然後master節點關閉AOF,slave節點開啟AOF。
- 這樣的方式的風險是如果master挂掉,尚沒有同步到salve的資料會丢失。而且 叢集選舉時,aof配置怎麼根據選舉結果動态修改修改,可能需要手動上去改一遍。感覺運維成本比較大。
- 閑的時間定時重寫、提升伺服器io性能
-
- 在淩晨低峰期定時手動執行
指令完成每日一次的bgrewriteaof
重寫AOF
- 比如使用ssd
- 在淩晨低峰期定時手動執行
-
-
- 将配置設為no
- 硬碟采用高速固态硬碟SSD
-
-
- 如果是三方伺服器,購買私有或者使用者隔離的混合雲,不要購買共有雲,不要讓其他使用者影響該伺服器磁盤穩定性
- 上監控人工介入,監控所有系統必不可少的一部分。
-
- 在重寫時為了避免硬碟空間不足或者
使用率高影響重寫功能,我們還添加了硬碟空間報警和IO
使用率報警保IO
- 在重寫時為了避免硬碟空間不足或者