温馨提示×

温馨提示×

您好,登录后才能下订单哦!

密码登录×
登录注册×
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》

Redis因为开了AOF导致hang住的问题处理

发布时间:2020-03-16 13:30:08 来源:网络 阅读:5872 作者:emma_cql 栏目:关系型数据库

问题描述

业务反馈正常有个接口正常访问在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


向AI问一下细节

免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

AI