程序项目代做,有需求私信(小程序、网站、爬虫、电路板设计、驱动、应用程序开发、毕设疑难问题处理等)

磁盘IO性能分析

一、IO性能分析

1.1 IO性能、顺序访问和随机访问

如果去看硬盘厂商的性能报告,通常你会看到两个指标;

  • 一个是响应时间(Response Time);
  • 另一个叫作数据传输率(Data Transfer Rate),数据传输率也称吞吐率。
1.1.1 数据传输率

我们先来看一看后面这个指标,数据传输率。

我们现在常用的硬盘有两种;

  • 一种是HDDHard Disk Drive)硬盘,也就是我们常说的机械硬盘;现在的HDD硬盘,用的是SATA 3.0的接口;
  • 另一种是SSDSolid State Drive)硬盘,一般也被叫作固态硬盘;而SSD 硬盘呢,通常会用两种接口:
    • 一部分用的也是SATA 3.0的接口;
    • 另一部分呢,用的是PCI Express的接口。

现在我们常用的SATA 3.0的接口,带宽是6Gb/s;这里的b是比特,这个带宽相当于每秒可以传输600MB的数据。

而我们日常用的HDD硬盘的数据传输率,差不多在100~200MB/s左右。比如:

1.1.2 响应时间

除了数据传输率这个吞吐率指标,另一个我们关心的指标响应时间,其实也可以在AS SSD的测试结果里面看到,就是这里面的Acc.Time指标。

这个指标,其实就是程序发起一个硬盘的写入请求,直到这个请求返回的时间。

可以看到,在上面的SSD硬盘上,大概时间都是在几十微秒这个级别。

如果你去测试一块HDD的硬盘,通常会在几毫秒到十几毫秒这个级别。这个性能的差异,就不是10倍了,而是在几十倍,乃至几百倍。

光看响应时间和吞吐率这两个指标,似乎我们的硬盘性能很不错。即使是廉价的HDD硬盘,接收一个来自CPU的请求,也能够在几毫秒时间返回。一秒钟能够传输的数据,也有200MB左右。你想一想,我们平时往数据库里写入一条记录,也就是1KB左右的大小。我们拿200MB去除以1KB,那差不多每秒钟可以插入20万条数据呢。但是这个计算出来的数字,似乎和我们日常的经验不符合啊?这又是为什么呢?

答案就来自于硬盘的读写。在顺序读写和随机读写的情况下,硬盘的性能是完全不同的。

我们回头看一下上面的AS SSD的性能指标。你会看到,里面有一个4K的指标。这个指标是什么意思呢?它其实就是我们的程序,去随机读取磁盘上某一个4KB 大小的数据,一秒之内可以读取到多少数据。

我们拿这个36MB/s和一次读取4KB的数据算一下。

36MB / 4KB = 9000

也就是说,一秒之内,这块SSD硬盘可以随机读取9000次的4KB的数据。如果是写入的话呢,会更多一些65MB /4KB 差不多是1.6万多次。

1.1.3 IOPS

这个每秒读写的次数,我们称之为IOPS,也就是每秒输入输出操作的次数。事实上,比起响应时间,我们更关注IOPS这个性能指标。

IOPSDTRData Transfer Rate,数据传输率)才是输入输出性能的核心指标。

IOPS可细分为如下几个指标:

  • Toatal IOPS:混合读写和顺序随机I/O负载情况下的磁盘IOPS,这个与实际I/O情况最为相符,大多数应用关注此指标;
  • Random Read IOPS100%随机读负载情况下的IOPS
  • Random Write IOPS100%随机写负载情况下的IOPS
  • Sequential Read IOPS100%顺序读负载情况下的IOPS
  • Sequential Write IOPS100%顺序写负载情况下的IOPS

我们在实际的应用开发当中,对于数据的访问,更多的是随机读写,而不是顺序读写。我们平时所说的服务器承受的并发,其实是在说,会有很多个不同的进程和请求来访问服务器。自然,它们在硬盘上访问的数据,是很难顺序放在一起的。这种情况下,随机读写的IOPS才是服务器性能的核心指标。

好了,回到我们引出IOPS这个问题的HDD硬盘,那一块HDD硬盘能够承受的IOPS是多少呢?

HDD硬盘的IOPS通常也就在160左右,而SSDIOPS大约在10,000-75,000之间,取决于具体的SSD和它的工作负载。

1.2 如何定位IO_WAIT

对于上图那款SSD硬盘,IOPS也就是在1.6万左右。而我们的CPU的主频通常在2GHz以上,也就是每秒可以做20亿次操作。

即使CPU向硬盘发起一条读写指令,需要很多个时钟周期,一秒钟CPU能够执行的指令数,和我们硬盘能够进行的操作数,也有好几个数量级的差异。

这也是为什么,我们在应用开发的时候往往会说性能瓶颈在I/O上。因为很多时候,CPU指令发出去之后,不得不去等我们的I/O操作完成,才能进行下一步的操作。

那么,在实际遇到服务端程序的性能问题的时候,我们怎么知道这个问题是不是来自于CPUI/O来完成操作呢?

别着急,我们接下来我们以我们测试环境遇到的IO问题为例,就通过topiostat这些命令,一起来看看CPU到底有没有在等待io操作。

1.2.1 top

Linux下经常会用top去看服务的负载,也就是load averageload average(负载平均值)是一个重要的性能指标,它反映了系统在过去1分钟、5分钟和15分钟内的平均负载情况。

1.2.1.1 load average

load average 的三个值通常显示在任务栏的第一行中:

  • 第一个值 (1分钟内的平均负载):这个值表示最近1分钟内正在运行和等待运行的进程的平均数量;如果这个值持续高于系统的CPU核心数(例如,如果你有4核CPU,1分钟平均负载超过4),则系统可能会感觉到响应变慢;
  • 第二个值 (5分钟内的平均负载):这个值显示了最近5分钟内的平均负载情况,它可以帮助你观察到系统负载的长期趋势;
  • 第三个值 (15分钟内的平均负载):这个值是最近15分钟内的平均负载情况,通常用来判断系统负载的趋势和变化;

通常来说,如果load average长期超过系统的CPU核心数(尤其是1分钟和5分钟的值),系统可能会感到卡顿或响应变慢,这时候需要进一步检查系统的资源使用情况和可能的性能瓶颈。

通过上图看到load average显示高于系统的核心数(96核),并且持续较长时间。

此外我们机器内存251G,目前剩余只有3G左右,导致服务器输入命令存在严重卡顿问题。

1.2.1.2 各个参数

此外,我们可以通过数字键1调出CPU的资源使用情况。

top命令的输出结果里面,有一行是以%CPU开头的。下面是各个百分比的含义:

  • us(userspace):用户空间的程序所消耗的CPU时间百分比,这表示正在运行的用户进程(非内核进程)所使用的CPU时间;

  • sy(system):内核空间的程序所消耗的CPU时间百分比。这表示正在运行的内核进程所使用的CPU时间,如系统调用、中断处理等;

  • ni(nice):通过nice命令设置了较低优先级的进程所消耗的CPU时间百分比;在这个报告中,该项值为0.1

  • id(idle):空闲状态的CPU时间百分比,这表示CPU未被任何任务占用的时间;

  • wa(waiting):等待I/O完成的CPU时间百分比,这表示CPU在等待磁盘或其他I/O设备完成操作时所使用的时间;

  • hi(hardwareinterrupts):硬件中断所消耗的CPU时间百分比。这表示CPU在处理硬件中断请求时所使用的时间;

  • si(softwareinterrupts):软件中断所消耗的CPU时间百分比。这表示CPU在处理软件中断请求时所使用的时间;

  • st(stealtime):当运行在虚拟化环境中的虚拟机被物理主机偷取CPU时间时所消耗的CPU时间百分比;

这一行里,有一个叫作wa的指标,这个指标就代表着iowait,也就是CPU等待IO完成操作花费的时间占 CPU的百分比。如果wa值很高,说明系统中有大量的I/O操作占用了CPU时间,导致CPU无法及时处理其他任务,从而影响系统性能。

当系统中有大量的进程在运行时,只有一小部分进程是I/O密集型进程,即依赖磁盘I/O的进程,而其余进程主要是CPU密集型进程,即需要大量的计算资源的进程。因此,在这种情况下,即使磁盘已经达到了最大的吞吐量,wa指标值也可能很低,因为系统中大多数进程并不需要等待磁盘I/O的完成。

下一次,当你自己的服务器遇到性能瓶颈,load很大的时候,你就可以通过top看一看这个指标。

知道了iowait很大,那么我们就要去看一看,实际的I/O操作情况是什么样的。这个时候,你就可以去用iostat这个命令了。

1.2.2 iostat

iotop命令看到实际的硬盘读写情况,这个命令里,不仅有iowait这个CPU等待时间的百分比,还有一些更加具体的指标了,并且它还是按照你机器上安装的多块不同的硬盘划分的。

iostat查看系统IO指标:

iostat -dx 1

其中:

  • Device:磁盘设备名称;
  • rrqm/s:每秒钟发起的读请求被合并为更大的请求的数量;
  • wrqm/s:每秒钟发起的写请求被合并为更大的请求的数量;
  • r/s:每秒钟发起的读请求的数量;
  • w/s:每秒钟发起的写请求的数量;
  • rkB/s:每秒钟读取的数据量,单位为KB
  • wkB/s:每秒钟写入的数据量,单位为KB
  • avgrq-sz:平均请求大小,单位为扇区大小(一般为512字节);
  • avgqu-sz:平均请求队列长度;
  • await:平均请求等待时间,单位为毫秒;
  • r_await:平均读请求等待时间,单位为毫秒;
  • w_await:平均写请求等待时间,单位为毫秒;
  • svctm:平均请求处理时间,单位为毫秒;
  • %util:磁盘处理I/O的时间百分比,即设备正在处理请求的时间占总时间的百分比;

其中重点关注:

  • r/s + w/s就是IOPS,即每秒读写次数;
  • rkB/s + wkB/s就是吞吐量,即每秒读写数据量;对应着我们的数据传输率的指标;
  • r_await + w_await,就是响应时间,即指I/O请求从发出到收到响应的间隔时间;

知道实际硬盘读写的IOPS、数据传输率的指标,我们基本上可以判断出,机器的性能是不是卡在I/O上了。

如果util字段显示为100%,表示磁盘正在以最大速度处理请求,也就是说磁盘已经达到了最大的吞吐量。这意味着磁盘已经成为系统中的瓶颈,无法再处理更多的I/O请求。这种情况下,应该考虑增加更多的磁盘或者使用更快的存储设备来提高系统性能。同时,也可以尝试优化应用程序的I/O操作,减少对磁盘的访问,从而降低磁盘的负载。

此前,我们提到过我们机器内存251G,只剩下3G左右,导致服务器输入命令存在严重卡顿问题。后面停止到一些进程后,服务运行正常,内存占用如下;

[root@kylin ~]$ free -h -m
              total        used        free      shared  buff/cache   available
Mem:           251G        116G         13G        4.8G        121G        128G
Swap:            0B          0B          0B

再次通过iostat查看系统IO指标:

可以看到此时的wkB/s可以达到上百MB,远高于服务器卡顿时的10~20MB

1.2.3 iotop

如果机器的性能卡在了I/O上,通过iotop这个命令,可以看到具体是哪一个进程实际占用了大量I/O

sudo iotop -o -b | while read -r line;do echo "$line" | grep 'Actual DISKWRITE';done
sudo iotop -oP

其中:

  • -o: only show processes or threads actually doing I/O
  • -Ponly show processes, not all threads
  • -kuse kilobytes instead of a human friendly unit
  • -bnon-interactive mode

前两行分别表示,进程的磁盘读写大小总数和磁盘真实的读写大小总数。因为缓存、缓冲区、I/O合并等因素的影响,它们可能并不相等。

如果进程IO等待时间过长(比如80%),大概率磁盘IO到了瓶颈,来不及处理。

关注一下Actual DISK WRITE这个参数,可以参考4K指标的值,如果超过这个值,这台机器的磁盘I/O基本就满了;可以结合夜莺看一下I/O是否满了。

1.3 慢SQL

有时候存在数据库慢SQL导致其他进程请求超时,PGSQL查询;

select *
from pg_stat_activity
where state <> 'idle'
  and now() - query_start > interval '1s'
order by query_start;

可以看到是否存在慢SQL,以及该SQL是否一次请求了万级别以上的数据。

二、jbd2进程导致磁盘IO

在服务器发现业务进程偶尔响应超时,排查后发现磁盘的sdb util接近100%

但是磁盘吞吐量并不高,IO流量只有6MB左右,主要是由w/s导致,也就是写入的IOPS高,这种情况一般就是进程的sync操作密集。

2.1 iotop

通过iotop来查看是哪个进程,显示为jbd2

查阅一些资料后,了解到jbd2进程负责ext4这种日志文件系统的日志提交操作,关于jbd2引起磁盘IO高,网上也有很多类似案例,总结起来有几方面原因:

  • 系统bug
  • ext4文件系统的相关配置问题;
  • 其他进程的fsyncsync操作过于频繁;

首先排除系统bug因素,网络上反馈的问题在很低的版本,我们生产环境为Centos 7+,其次,查阅了/proc/mounts等信息,发现文件系统配置参数与其他环境差异不大,按照网上提供的关闭某些特性,降低commit 频率等理论来说会有效果,但需要重新mount磁盘,相关组件都要重启,并且这看起来并非根本原因。

2.2 sync

尝试分析sync调用,使用sysdig最方便,但现场环境安装很麻烦,因此开启几个内核trace查看:

jbd2执行flush时输出日志

echo 1 > /sys/kernel/debug/tracing/events/jbd2/jbd2_commit_flushing/enable

在任意进程执行sync时输出日志:

echo 1 > /sys/kernel/debug/tracing/events/ext4/ext4_sync_file_enter/enable 

然后观察日志输出:

cat /sys/kernel/debug/tracing/trace_pipe 

输出信息如下:

可以看到jbd292350进程有大量的sync,瞬间刷出大量日志,因此基本确定92350进程。

ps看一下是哪个任务导致的:

ps -efL | grep 92350

-L-T参数显示线程idps获取到pid和程序路径后,发现是XX进程,很让人疑惑,XX怎么会大量sync 呢,trace 一下他在做什么。

2.3 strace

亲爱的读者和支持者们,自动博客加入了打赏功能,陆陆续续收到了各位老铁的打赏。在此,我想由衷地感谢每一位对我们博客的支持和打赏。你们的慷慨与支持,是我们前行的动力与源泉。

日期姓名金额
2023-09-06*源19
2023-09-11*朝科88
2023-09-21*号5
2023-09-16*真60
2023-10-26*通9.9
2023-11-04*慎0.66
2023-11-24*恩0.01
2023-12-30I*B1
2024-01-28*兴20
2024-02-01QYing20
2024-02-11*督6
2024-02-18一*x1
2024-02-20c*l18.88
2024-01-01*I5
2024-04-08*程150
2024-04-18*超20
2024-04-26.*V30
2024-05-08D*W5
2024-05-29*辉20
2024-05-30*雄10
2024-06-08*:10
2024-06-23小狮子666
2024-06-28*s6.66
2024-06-29*炼1
2024-06-30*!1
2024-07-08*方20
2024-07-18A*16.66
2024-07-31*北12
2024-08-13*基1
2024-08-23n*s2
2024-09-02*源50
2024-09-04*J2
2024-09-06*强8.8
2024-09-09*波1
2024-09-10*口1
2024-09-10*波1
2024-09-12*波10
2024-09-18*明1.68
2024-09-26B*h10
2024-09-3010
2024-10-02M*i1
2024-10-14*朋10
2024-10-22*海10
2024-10-23*南10
2024-10-26*节6.66
2024-10-27*o5
2024-10-28W*F6.66
2024-10-29R*n6.66
2024-11-02*球6
2024-11-021*鑫6.66
2024-11-25*沙5
2024-11-29C*n2.88
posted @   大奥特曼打小怪兽  阅读(443)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· DeepSeek 开源周回顾「GitHub 热点速览」
· 记一次.NET内存居高不下排查解决与启示
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
历史上的今天:
2018-08-03 集成学习值Adaboost算法原理和代码小结(转载)
2018-08-03 集成学习原理小结(转载)
2018-08-03 2019阿里校招测评题,光明小学完全图最短路径问题(python实现)
如果有任何技术小问题,欢迎大家交流沟通,共同进步

公告 & 打赏

>>

欢迎打赏支持我 ^_^

最新公告

程序项目代做,有需求私信(小程序、网站、爬虫、电路板设计、驱动、应用程序开发、毕设疑难问题处理等)。

了解更多

点击右上角即可分享
微信分享提示