问题描述
业务反馈正常有个接口正常访问在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
免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。