Redis因爲開了AOF導致hang住的問題處理

問題描述

業務反饋正常有個接口正常訪問在100ms以內,有時候調用時長會要10多s,根據業務提供的時間查redis日誌,以現有如下記錄:

8788:M 24 Aug 01:21:26.008 * 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.
8788:M 24 Aug 01:21:45.006 * 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.

查看redis aof相關配置

127.0.0.1:6390> config get *append*
1) "no-appendfsync-on-rewrite"
2) "yes"
3) "appendfsync"
4) "everysec"
5) "appendonly"
6) "yes"


查看rdb的配置:

127.0.0.1:6390> config get save
1) "save"
2) ""

 

 查看redis的版本:

 127.0.0.1:6390> info server
# Server
redis_version:3.2.4

 

故障分析

打開AOF持久化功能後, Redis處理完每個事件後會調用write(2)將變化寫入kernel的buffer,如果此時write(2)被阻塞,Redis就不能處理下一個事件。

Linux規定執行write(2)時,如果對同一個文件正在執行fdatasync(2)將kernel buffer寫入物理磁盤,或者有system wide sync在執行,write(2)會被Block住,整個Redis被Block住。

如果系統IO繁忙,比如有別的應用在寫盤,或者Redis自己在AOF rewrite或RDB snapshot(雖然此時寫入的是另一個臨時文件,雖然各自都在連續寫,但兩個文件間的切換使得磁盤磁頭的尋道時間加長),就可能導致fdatasync(2)遲遲未能完成從而Block住write(2),Block住整個Redis。

爲了更清晰的看到fdatasync(2)的執行時長,可以使用”strace -p (pid of redis server) -T -e -f trace=fdatasync”,但會影響系統性能。

Redis提供了一個自救的方式,當發現文件有在執行fdatasync(2)時,就先不調用write(2),只存在cache裏,免得被Block。但如果已經超過兩秒都還是這個樣子,則會硬着頭皮執行write(2),即使redis會被Block住。

此時那句要命的log會打印:“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.”

之後用redis-cli INFO可以看到aof_delayed_fsync的值被加1。

因此,對於fsync設爲everysec時丟失數據的可能性的最嚴謹說法是:如果有fdatasync在長時間的執行,此時redis意外關閉會造成文件裏不多於兩秒的數據丟失。

如果fdatasync運行正常,redis意外關閉沒有影響,只有當操作系統crash時纔會造成少於1秒的數據丟失。

 

 

解決方法

方法一:關閉aof

這個方法需要和業務確認是否可行,個人認爲如果採用redis主從+sentinel方式的話主節點掛了從節點會自己提升爲主點,主節點恢復後全量同步一次數據就可以了,關係也不是太大

方法二:修改系統配置

原來是AOF rewrite時一直埋頭的調用write(2),由系統自己去觸發sync。在RedHat Enterprise 6裏,默認配置vm.dirty_background_ratio=10,也就是佔用了10%的可用內存纔會開始後臺flush,而我的服務器有8G內存。

很明顯一次flush太多數據會造成阻塞,所以最後果斷設置了sysctl vm.dirty_bytes=33554432(32M),問題解決。

然後提了個issue,AOF rewrite時定時也執行一下fdatasync嘛, antirez回覆新版中,AOF rewrite時32M就會重寫主動調用fdatasync。

查看一下系統內核參數

>sysctl -a | grep dirty_background_ratio
vm.dirty_background_ratio = 10
>sysctl -a | grep vm.dirty_bytes
vm.dirty_bytes = 0

嘗試修改一下配置文件/etc/sysctl.conf,並使配置立即生效

echo "vm.dirty_bytes=33554432" >> /etc/sysctl.conf
sysctl -p

驗證修改是否成功

>sysctl -a | grep vm.dirty_bytes
vm.dirty_bytes = 33554432


 參考:

https://ningyu1.github.io/site/post/32-redis-aof/

https://redis.io/topics/latency


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