I/O分析系列--strace+lsof分析Redis对文件读写产生的iowait瓶颈

目录

strace -f -T -tt -p pid:用来监控某进程产生的系统调用.

lsof -p pid:输出某进程打开的所有文件.

1.排查wait态cpu使用率高的原因:

        1.查看是否是I/O负载高引起:iostat -d x 3

        2.排查IO请求的原因:pidstat -d 3

        3.定位到可能的问题:redis写数据造成iowait

        4.分析问题原因:strace -f -T -tt -p 4728,发现redis在不断的向文件写数据.

         5.输出redis进程打开的所有文件:lsof -p 4782

        6.7w-->/data/appendonly.aof文件分析显示redis在频繁写文件:

        7.查看redis的fsync配置:docker exec -it redis reidis-cli config get 'append*' 

8.分析read调用,代码中可能存在一个SADD方法:

9.分析代码:确认猜想

2.问题总结:

        1.Redis配置的"appendfsync"值为"always",导致Redis每次的写操作,都会触发fdatasync系统调用将数据持久化落入磁盘.

        2.应用代码中调用了Redis的sadd命令,这也可能造成缓存使用不合理的问题.

3.解决方案:

        1.将Redis配置的"appendfsync"值改为"everysec".

        docker exec -it redis redis-cli config set appendfsync everysec 

          修改后回归,发现iowait降低,响应时间大幅度减少,TPS随之升高.

        2.让研发优化代码.


在性能测试过程中,碰到的瓶颈并不一定都是cpu,mem造成,还有可能是系统架构设计不合理,代码算法性能差引起的.

strace -f -T -tt -p pid:用来监控某进程产生的系统调用.

lsof -p pid:输出某进程打开的所有文件.

安装strace:yum install -y strace

Redis性能瓶颈分析: 

性能测试时,发现tps低,响应时间很高,但是查看系统负载,cpu和mem都处于可控范围,排查压力机的负载和网络连通性,均正常,唯一异常的是wait态的cpu较高.

1.排查wait态cpu使用率高的原因:

        1.查看是否是I/O负载高引起:iostat -d x 3

         发现,I/O无性能瓶颈,但是压测的接口是一个读数据接口,此处io信息显示,在压测过程中,对磁盘有写的操作,需要排查是什么在压测过程中不断的写数据.

        2.排查IO请求的原因:pidstat -d 3

        显示redis-server这个进程在不断的写数据.但是redis一般被用来作为缓存中间件,提高查询时的返回速度,一般都只做读操作,所以需要排查为何redis在不断的写数据.

        3.定位到可能的问题:redis写数据造成iowait

        4.分析问题原因:strace -f -T -tt -p 4728,发现redis在不断的向文件写数据.

        发现redis有read,write,epoll_pwait,fdatasync等系统调用,且调用频繁,且write.fdatasync表示在不断地向文件写数据.

         5.输出redis进程打开的所有文件:lsof -p 4782

        lsof即可显示系统打开的文件,因为 lsof 需要访问核心内存和各种文件,所以必须以 root 用户的身份运行它才能够充分地发挥其功能。

         FD列描述:(linux万物皆文件)

                3r:一个pipe管道;        5u:eventpoll;        6u:一个tcp socket;        7w:一个普通文件

        6.7w-->/data/appendonly.aof文件分析显示redis在频繁写文件:

                redis数据持久化2种方式:

               1.快照方式:redis会按照指定的时间间隔生成数据的快照,然后保存在磁盘文件中,为了避免阻塞主进程,redis还会fork一个子进程,负责快照的保存,这种方式在备份和恢复,好于文件追加方式.                缺点:数据量大时,消耗内存,而且耗时.如果发生故障,会丢失数分钟的数据.

               2.追加文件:redis使用在文件末尾追加记录的方式,实现redis依次写入数据到磁盘,文件追加的方式使数据更安全.  追加文件的方式还提供了"appendfsync"选项设置fsync,来确保写入磁盘的数据的频率,选项包括:

                "always":每个操作都会执行一次fsync,最安全.

                "everysec":每秒执行一次fsync,就算数据丢失,也只丢失1s的数据.

                "no":交给操作系统处理.
           缺点:若选项使用"always"频繁的写入磁盘,会造成io负载高.

        7.查看redis的fsync配置:docker exec -it redis reidis-cli config get 'append*' 

                发现redis的appendfsync设置的是"always",造成了压测时每次写redis操作都会调用fsync写磁盘.这就造成了磁盘IO压力 

8.分析read调用,代码中可能存在一个SADD方法:

        而redis的SADD方法是一个写操作,所以猜测redis会把它写入到用于持久化的appendonly.aof文件中,找到了redis写磁盘的可能原因:代码中调用了redis的sadd方法.

9.分析代码:确认猜想

代码中确实存在调用redis的sadd方法.

2.问题总结:

        1.Redis配置的"appendfsync"值为"always",导致Redis每次的写操作,都会触发fdatasync系统调用将数据持久化落入磁盘.

        2.应用代码中调用了Redis的sadd命令,这也可能造成缓存使用不合理的问题.

3.解决方案:

        1.将Redis配置的"appendfsync"值改为"everysec".

        docker exec -it redis redis-cli config set appendfsync everysec 

          修改后回归,发现iowait降低,响应时间大幅度减少,TPS随之升高.

        2.让研发优化代码.

猜你喜欢

转载自blog.csdn.net/qq_40132294/article/details/121478770