当前位置:   article > 正文

磁盘IO性能到底是怎么回事儿?_磁盘吞吐和io wait指标

磁盘吞吐和io wait指标

目录

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

如何定位 IO_WAIT?

拆解机械硬盘

RAID


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

如果去看硬盘厂商的性能报告,通常你会看到两个指标。一个是响应时间(Response Time),另一个叫作数据传输率(Data Transfer Rate),数据传输率也称吞吐率。

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

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

现在我们常用的 SATA 3.0 的接口,带宽是 6Gb/s。这里的“b”是比特。这个带宽相当于每秒可以传输 768MB 的数据。而我们日常用的 HDD 硬盘的数据传输率,差不多在 200MB/s 左右。

除了数据传输率这个吞吐率指标,另一个我们关心的指标响应时间,其实也可以在 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 万多次。

这个每秒读写的次数,我们称之为 IOPS,也就是每秒输入输出操作的次数。事实上,比起响应时间,我们更关注 IOPS 这个性能指标。IOPS 和 DTR(Data Transfer Rate,数据传输率)才是输入输出性能的核心指标

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

好了,回到我们引出 IOPS 这个问题的 HDD 硬盘。那一块 HDD 硬盘能够承受的 IOPS 是多少呢?HDD 硬盘的 IOPS 通常也就在 100 左右,而不是在 20 万次。

如何定位 IO_WAIT?

我们看到,即使是用上了 PCI Express 接口的 SSD 硬盘,IOPS 也就是在 1.6 万左右。而我们的 CPU 的主频通常在 2GHz 以上,也就是每秒可以做 20 亿次操作。

即使 CPU 向硬盘发起一条读写指令,需要很多个时钟周期,一秒钟 CPU 能够执行的指令数,和我们硬盘能够进行的操作数,也有好几个数量级的差异。这也是为什么,我们在应用开发的时候往往会说“性能瓶颈在 I/O 上”。因为很多时候,CPU 指令发出去之后,不得不去“等”我们的 I/O 操作完成,才能进行下一步的操作。

那么,在实际遇到服务端程序的性能问题的时候,我们怎么知道这个问题是不是来自于 CPU 等 I/O 来完成操作呢?别着急,我们接下来,就通过 top 和 iostat 这些命令,一起来看看 CPU 到底有没有在等待 io 操作。

# top

你一定在 Linux 下用过 top 命令。经常会用 top 去看服务的负载,也就是 load average。不过,在 top 命令里面,我们一样可以看到 CPU 是否在等待 IO 操作完成。

  1. top - 06:26:30 up 4 days, 53 min, 1 user, load average: 0.79, 0.69, 0.65
  2. Tasks: 204 total, 1 running, 203 sleeping, 0 stopped, 0 zombie
  3. %Cpu(s): 20.0 us, 1.7 sy, 0.0 ni, 77.7 id, 0.0 wa, 0.0 hi, 0.7 si, 0.0 st
  4. KiB Mem: 7679792 total, 6646248 used, 1033544 free, 251688 buffers
  5. KiB Swap: 0 total, 0 used, 0 free. 4115536 cached Mem

在 top 命令的输出结果里面,有一行是以 %CPU 开头的。这一行里,有一个叫作 wa 的指标,这个指标就代表着 iowait,也就是 CPU 等待 IO 完成操作花费的时间占 CPU 的百分比。下一次,当你自己的服务器遇到性能瓶颈,load 很大的时候,你就可以通过 top 看一看这个指标。

知道了 iowait 很大,那么我们就要去看一看,实际的 I/O 操作情况是什么样的。这个时候,你就可以去用 iostat 这个命令了。我们输入“iostat”,就能够看到实际的硬盘读写情况。

  1. [root@k8s-master1 storagedisk]# iostat
  2. Linux 3.10.0-1160.102.1.el7.x86_64 (k8s-master1) 01/03/2024 _x86_64_ (64 CPU)
  3. avg-cpu: %user %nice %system %iowait %steal %idle
  4. 15.90 0.02 6.45 0.07 0.00 77.56
  5. Device: tps kB_read/s kB_wrtn/s kB_read kB_wrtn
  6. sdb 34.53 0.59 1760.09 51008 152619264
  7. sda 71.41 104.77 3504.61 9084729 303888228
  8. sdc 237.12 117.64 8665.65 10200872 751406236

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

这里的 tps 指标,其实就对应着我们上面所说的硬盘的 IOPS 性能。而 kB_read/s 和 kB_wrtn/s 指标,就对应着我们的数据传输率的指标。

知道实际硬盘读写的 tps、kB_read/s 和 kb_wrtn/s 的指标,我们基本上可以判断出,机器的性能是不是卡在 I/O 上了。那么,接下来,我们就是要找出到底是哪一个进程是这些 I/O 读写的来源了。这个时候,你需要“iotop”这个命令。

# iotop
  1. Total DISK READ : 63.44 K/s | Total DISK WRITE : 31.72 M/s
  2. Actual DISK READ: 10.57 K/s | Actual DISK WRITE: 292.62 M/s
  3. PID PRIO USER DISK READ DISK WRITE> SWAPIN IO COMMAND
  4. 127673 be/4 root 0.00 B 117.38 M 0.00 % 0.00 % weed volume -ip=seaweedfs-volume-0.seaweedfs-volume.component.svc.c~er-0.seaweedfs-master:9333 -max=1000 -dir=/weed/data/volume -rack=0
  5. 106652 ?dif 1000 6.93 M 46.89 M 0.00 % 0.26 % java -Xms1g -Xmx1g -XX:+UseConcMarkSweepGC -XX:CMSInitiatingOccupan~share/elasticsearch/lib/* org.elasticsearch.bootstrap.Elasticsearch
  6. 122162 be/4 root 0.00 B 22.94 M 0.00 % 0.00 % java -Xmx5120M -Xms5120M -Xmn3096M -server -XX:+UseG1GC -XX:MaxGCPa~ar:/opt/kafka/bin/../libs/metrics-core-2.2.0.jar:/opt/kafka/bin/../
  7. 45293 be/4 26 0.00 B 2.83 M 0.00 % 0.14 % postgres: pg-ha: postgres postgres 10.244.0.25(48878) idle
  8. 110070 be/4 root 0.00 B 2.51 M 0.00 % 0.00 % java -Dcassandra.allow_unsafe_aggressive_sstable_expiration=true -D~cal/apache-cassandra-3.11.13/lib/snowball-stemmer-1.3.0.581.1.jar:/
  9. 90970 be/4 26 0.00 B 2.45 M 0.00 % 0.16 % postgres: pg-ha: postgres postgres 10.244.0.25(35416) idle
  10. 40359 be/4 root 0.00 B 1712.00 K 0.00 % 0.00 % dockerd -H fd:// --containerd=/run/containerd/containerd.sock
  11. 107508 be/4 10001 0.00 B 1192.00 K 0.00 % 0.00 % loki -config.file=/etc/loki/config/config.yaml -target=ingester

通过 iotop 这个命令,你可以看到具体是哪一个进程实际占用了大量 I/O,那么你就可以有的放矢,去优化对应的程序了。

可以自己通过linux stress命令模拟压测一下服务器的I/O性能瓶颈。

关于 IO_WAIT 的文章,在互联网上已经有不少了。你可以读一读这一篇 Understanding IOPS Latency and Storage Performance,进一步理解一下什么是 IOPS 和 IO_WAIT。

拆解机械硬盘

上面我们提到过机械硬盘的 IOPS。我们说,机械硬盘的 IOPS,大概只能做到每秒 100 次左右。那么,这个 100 次究竟是怎么来的呢?

我们把机械硬盘拆开来看一看,看看它的物理构造是怎么样的,你就自然知道为什么它的 IOPS 是 100 左右了。

一块机械硬盘是由盘面、磁头和悬臂三个部件组成的。下面我们一一来看每一个部件。

首先,自然是盘面(Disk Platter)。盘面其实就是我们实际存储数据的盘片。如果你剪开过软盘的外壳,或者看过光盘 DVD,那你看到盘面应该很熟悉。盘面其实和它们长得差不多。

盘面本身通常是用的铝、玻璃或者陶瓷这样的材质做成的光滑盘片。然后,盘面上有一层磁性的涂层。我们的数据就存储在这个磁性的涂层上。盘面中间有一个受电机控制的转轴。这个转轴会控制我们的盘面去旋转。

我们平时买硬盘的时候经常会听到一个指标,叫作这个硬盘的转速。我们的硬盘有 5400 转的、7200 转的,乃至 10000 转的。这个多少多少转,指的就是盘面中间电机控制的转轴的旋转速度,英文单位叫 RPM,也就是每分钟的旋转圈数(Rotations Per Minute)。所谓 7200 转,其实更准确地说是 7200RPM,指的就是一旦电脑开机供电之后,我们的硬盘就可以一直做到每分钟转上 7200 圈。如果折算到每一秒钟,就是 120 圈。

说完了盘面,我们来看磁头(Drive Head)。我们的数据并不能直接从盘面传输到总线上,而是通过磁头,从盘面上读取到,然后再通过电路信号传输给控制电路、接口,再到总线上的。

通常,我们的一个盘面上会有两个磁头,分别在盘面的正反面。盘面在正反两面都有对应的磁性涂层来存储数据,而且一块硬盘也不是只有一个盘面,而是上下堆叠了很多个盘面,各个盘面之间是平行的。每个盘面的正反两面都有对应的磁头。

最后我们来看悬臂(Actutor Arm)。悬臂链接在磁头上,并且在一定范围内会去把磁头定位到盘面的某个特定的磁道(Track)上。这个磁道是怎么来呢?想要了解这个问题,我们要先看一看我们的数据是怎么存放在盘面上的。

一个盘面通常是圆形的,由很多个同心圆组成,就好像是一个个大小不一样的“甜甜圈”嵌套在一起。每一个“甜甜圈”都是一个磁道。每个磁道都有自己的一个编号。悬臂其实只是控制,到底是读最里面那个“甜甜圈”的数据,还是最外面“甜甜圈”的数据。

知道了我们硬盘的物理构成,现在我们就可以看一看,这样的物理结构,到底是怎么来读取数据的。

我们刚才说的一个磁道,会分成一个一个扇区(Sector)。上下平行的一个一个盘面的相同扇区呢,我们叫作一个柱面(Cylinder)。

读取数据,其实就是两个步骤。一个步骤,就是把盘面旋转到某一个位置。在这个位置上,我们的悬臂可以定位到整个盘面的某一个子区间。这个子区间的形状有点儿像一块披萨饼,我们一般把这个区间叫作几何扇区(Geometrical Sector),意思是,在“几何位置上”,所有这些扇区都可以被悬臂访问到。另一个步骤,就是把我们的悬臂移动到特定磁道的特定扇区,也就在这个“几何扇区”里面,找到我们实际的扇区。找到之后,我们的磁头会落下,就可以读取到正对着扇区的数据。

所以,我们进行一次硬盘上的随机访问,需要的时间由两个部分组成。

第一个部分,叫作平均延时(Average Latency)。这个时间,其实就是把我们的盘面旋转,把几何扇区对准悬臂位置的时间。这个时间很容易计算,它其实就和我们机械硬盘的转速相关。随机情况下,平均找到一个几何扇区,我们需要旋转半圈盘面。上面 7200 转的硬盘,那么一秒里面,就可以旋转 240 个半圈。那么,这个平均延时就是

1s / 240 = 4.17ms

第二个部分,叫作平均寻道时间(Average Seek Time),也就是在盘面旋转之后,我们的悬臂定位到扇区的的时间。我们现在用的 HDD 硬盘的平均寻道时间一般在 4-10ms。

这样,我们就能够算出来,如果随机在整个硬盘上找一个数据,需要 8-14 ms。我们的硬盘是机械结构的,只有一个电机转轴,也只有一个悬臂,所以我们没有办法并行地去定位或者读取数据。那一块 7200 转的硬盘,我们一秒钟随机的 IO 访问次数,也就是

1s / 8 ms = 125 IOPS 或者 1s / 14ms = 70 IOPS

现在,你明白我们上面讲所说的,HDD 硬盘的 IOPS 每秒 100 次左右是怎么来的吧?

想要对机械硬盘的各种性能指标有更深入的理解,你可以读一读 Symantec 写的 Getting The Hang Of IOPS 的白皮书。

RAID

企业上使用硬盘,一般都会做RAID,来提供更高的存储性能和数据冗余方案。可以阅读我的另一篇文章 磁盘RAID级别选择指南

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/IT小白/article/detail/608909
推荐阅读
相关标签
  

闽ICP备14008679号