Skip to content

Commit 57e7bd9

Browse files
author
wangyazhou
committed
新增磁盘I/O说明
1 parent bb0ed37 commit 57e7bd9

File tree

4 files changed

+110
-1
lines changed

4 files changed

+110
-1
lines changed

linux/Pasted image 20250627181937.png.md

Whitespace-only changes.
236 KB
Loading
259 KB
Loading

linux/linux-performance.md

Lines changed: 110 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -868,15 +868,124 @@ df -i /dev/sfa1
868868
869869
870870
## 磁盘I/O
871+
磁盘是可以持久化存储的设备,根据存储介质的不同,常见磁盘可以分为两类:机械磁盘(Hard Disk Driver)和固态磁盘(Solid State Disk)。
871872
873+
### 磁盘IO原理
874+
第一类,机械磁盘,也称为硬盘驱动器(Hard Disk Driver),通常缩写为 HDD。机械磁盘主要由盘片和读写磁头组成,数据就存储在盘片的环状磁道中。在读写数据前,需要移动读写磁头,定位到数据所在的磁道,然后才能访问数据。
872875
876+
显然,如果 I/O 请求刚好连续,那就不需要磁道寻址,自然可以获得最佳性能。这其实就是我们熟悉的,连续 I/O 的工作原理。与之相对应的,当然就是随机 I/O,它需要不停地移动磁头,来定位数据位置,所以读写速度就会比较慢。
877+
878+
第二类,固态磁盘(Solid State Disk),通常缩写为 SSD,由固态电子元器件组成。固态磁盘不需要磁道寻址,所以,不管是连续 I/O,还是随机 I/O 的性能,都比机械磁盘要好得多。
879+
880+
其实,无论机械磁盘,还是固态磁盘,相同磁盘的随机 I/O 都要比连续 I/O 慢很多,原因也很明显。
881+
- 对机械磁盘来说,我们刚刚提到过的,由于随机 I/O 需要更多的磁头寻道和盘片旋转,它的性能自然要比连续 I/O 慢。
882+
- 而对固态磁盘来说,虽然它的随机性能比机械硬盘好很多,但同样存在“先擦除再写入”的限制。随机读写会导致大量的垃圾回收,所以相对应的,随机 I/O 的性能比起连续 I/O 来,也还是差了很多
883+
- 此外,连续 I/O 还可以通过预读的方式,来减少 I/O 请求的次数,这也是其性能优异的一个原因。很多性能优化的方案,也都会从这个角度出发,来优化 I/O 性能。
884+
885+
机械磁盘和固态磁盘还分别有一个最小的读写单位
886+
机械磁盘的最小读写单位是扇区,一般大小为 512 字节。而固态磁盘的最小读写单位是页,通常大小是 4KB、8KB 等
887+
888+
889+
#### 通用块层
890+
跟我们上一节讲到的虚拟文件系统 VFS 类似,为了减小不同块设备的差异带来的影响, Linux 通过一个统一的通用块层,来管理各种不同的块设备。
891+
892+
通用块层,其实是处在文件系统和磁盘驱动中间的一个块设备抽象层。它主要有两个功能
893+
- 第一个功能跟虚拟文件系统的功能类似。向上,为文件系统和应用程序,提供访问块设备的标准接口;向下,把各种异构的磁盘设备抽象为统一的块设备,并提供统一框架来管理这些设备的驱动程序。
894+
- 第二个功能,通用块层还会给文件系统和应用程序发来的 I/O 请求排队,并通过重新排序、请求合并等方式,提高磁盘读写的效率。
895+
896+
其中,对 I/O 请求排序的过程,也就是我们熟悉的 I/O 调度。事实上,Linux 内核支持四种 I/O 调度算法,分别是 NONE、NOOP、CFQ 以及 DeadLine。这里我也分别介绍一下
897+
898+
1. 第一种 NONE ,更确切来说,并不能算 I/O 调度算法。因为它完全不使用任何 I/O 调度器,对文件系统和应用程序的 I/O 其实不做任何处理,常用在虚拟机中(此时磁盘 I/O 调度完全由物理机负责)
899+
2. 第二种 NOOP ,是最简单的一种 I/O 调度算法。它实际上是一个先入先出的队列,只做一些最基本的请求合并,常用于 SSD 磁盘。
900+
3. 第三种 CFQ(Completely Fair Scheduler),也被称为完全公平调度器,是现在很多发行版的默认 I/O 调度器,它为每个进程维护了一个 I/O 调度队列,并按照时间片来均匀分布每个进程的 I/O 请求。类似于进程 CPU 调度,CFQ 还支持进程 I/O 的优先级调度,所以它适用于运行大量进程的系统,像是桌面环境、多媒体应用等
901+
4. 最后一种 DeadLine 调度算法,分别为读、写请求创建了不同的 I/O 队列,可以提高机械磁盘的吞吐量,并确保达到最终期限(deadline)的请求被优先处理。DeadLine 调度算法,多用在 I/O 压力比较重的场景,比如数据库等
902+
903+
通用块层是 Linux 磁盘 I/O 的核心。向上,它为文件系统和应用程序,提供访问了块设备的标准接口;向下,把各种异构的磁盘设备,抽象为统一的块设备,并会对文件系统和应用程序发来的 I/O 请求,进行重新排序、请求合并等,提高了磁盘访问的效率。
873904
874-
### 磁盘IO原理
875905
#### 磁盘管理
876906
#### 磁盘类型
877907
#### 磁盘接口
878908
#### 磁盘I/O栈
909+
我们可以把 Linux 存储系统的 I/O 栈,由上到下分为三个层次,分别是文件系统层、通用块层和设备层。这三个 I/O 层的关系如下图所示,这其实也是 Linux 存储系统的 I/O 栈全景图。
910+
![[Pasted image 20250627182100.png]]
911+
图片来源 [https://www.thomas-krenn.com/en/wiki/Linux_Storage_Stack_Diagram](https://www.thomas-krenn.com/en/wiki/Linux_Storage_Stack_Diagram)
912+
913+
文件系统层,包括虚拟文件系统和其他各种文件系统的具体实现。它为上层的应用程序,提供标准的文件访问接口;对下会通过通用块层,来存储和管理磁盘数据
914+
通用块层,包括块设备 I/O 队列和 I/O 调度器。它会对文件系统的 I/O 请求进行排队,再通过重新排序和请求合并,然后才要发送给下一级的设备层。
915+
设备层,包括存储设备和相应的驱动程序,负责最终物理设备的 I/O 操作。
916+
917+
879918
### 性能指标
919+
说到磁盘性能的衡量标准,必须要提到五个常见指标,也就是我们经常用到的,使用率、饱和度、IOPS、吞吐量以及响应时间等。这五个指标,是衡量磁盘性能的基本指标。
920+
921+
- 使用率,是指磁盘处理 I/O 的时间百分比。过高的使用率(比如超过 80%),通常意味着磁盘 I/O 存在性能瓶颈。
922+
- 饱和度,是指磁盘处理 I/O 的繁忙程度。过高的饱和度,意味着磁盘存在严重的性能瓶颈。当饱和度为 100% 时,磁盘无法接受新的 I/O 请求。
923+
- IOPS(Input/Output Per Second),是指每秒的 I/O 请求数。
924+
- 吞吐量,是指每秒的 I/O 请求大小。
925+
- 响应时间,是指 I/O 请求从发出到收到响应的间隔时间。
926+
这里要注意的是,使用率只考虑有没有 I/O,而不考虑 I/O 的大小。换句话说,当使用率是100% 的时候,磁盘依然有可能接受新的 I/O 请求。
927+
928+
不要孤立地去比较某一指标,而要结合读写比例、I/O 类型(随机还是连续)以及I/O 的大小,综合来分析。
929+
举个例子,在数据库、大量小文件等这类随机读写比较多的场景中,IOPS 更能反映系统的整体性能;而在多媒体等顺序读写较多的场景中,吞吐量才更能反映系统的整体性能。
930+
931+
#### 磁盘I/O观测工具
932+
- fio 来测试磁盘的 IOPS、吞吐量以及响应时间等核心指标。
933+
- iostat 是最常用的磁盘 I/O 性能观测工具,它提供了每个磁盘的使用率、IOPS、吞吐量等各种常见的性能指标,当然,这些指标实际上来自 /proc/diskstats。
934+
```bash
935+
# -d -x 表示显示所有磁盘I/O的指标
936+
[~]$ iostat -d -x 1
937+
Linux 5.14.0-427.13.1.el9_4.x86_64 (package.testocpdc1.shdc1.com) 06/27/2025 _x86_64_ (16 CPU)
938+
939+
Device r/s rkB/s rrqm/s %rrqm r_await rareq-sz w/s wkB/s wrqm/s %wrqm w_await wareq-sz d/s dkB/s drqm/s %drqm d_await dareq-sz f/s f_await aqu-sz %util
940+
dm-0 0.67 164.15 0.00 0.00 21.02 245.03 25.00 973.25 0.00 0.00 3.48 38.93 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.10 0.65
941+
sda 0.00 0.00 0.00 0.00 2.89 29.81 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00
942+
sdb 0.70 164.18 0.08 10.28 21.51 233.21 10.29 973.25 15.37 59.90 7.21 94.55 0.00 0.00 0.00 0.00 0.00 0.00 2.41 0.33 0.09 0.67
943+
sr0 0.00 0.00 0.00 0.00 0.07 42.08 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00
944+
```
945+
946+
![[Pasted image 20250627184607.png]]
947+
948+
- %util ,就是我们前面提到的磁盘 I/O 使用率;
949+
- r/s+ w/s ,就是 IOPS;
950+
- rkB/s+wkB/s ,就是吞吐量;
951+
- r_await+w_await ,就是响应时间
952+
953+
在观测指标时,也别忘了结合请求的大小( rareq-sz 和 wareq-sz)一起分析。
954+
955+
你可能注意到,从 iostat 并不能直接得到磁盘饱和度。事实上,饱和度通常也没有其他简单的观测方法,不过,你可以把观测到的,平均请求队列长度或者读写请求完成的等待时间,跟基准测试的结果(比如通过 fio)进行对比,综合评估磁盘的饱和情况。
956+
957+
#### 进程I/O观测
958+
除了每块磁盘的 I/O 情况,每个进程的 I/O 情况也是我们需要关注的重点
959+
上面提到的 iostat 只提供磁盘整体的 I/O 性能数据,缺点在于,并不能知道具体是哪些进程在进行磁盘读写。要观察进程的 I/O 情况,你还可以使用 pidstat 和 iotop 这两个工具
960+
961+
pidstat 是我们的老朋友了,这里我就不再啰嗦它的功能了。给它加上 -d 参数,你就可以看到进程的 I/O 情况,如下所示:
962+
```bash
963+
[~]$ pidstat -d
964+
Linux 5.14.0-427.13.1.el9_4.x86_64 (ubuntu) 06/27/2025 _x86_64_ (16 CPU)
965+
966+
06:49:45 PM UID PID kB_rd/s kB_wr/s kB_ccwr/s iodelay Command
967+
06:49:45 PM 1001 277531 0.00 0.00 0.00 0 systemd
968+
06:49:45 PM 1001 385588 0.00 0.00 0.00 0 bash
969+
06:49:45 PM 1001 456994 0.05 530.71 119.63 0 bash
970+
06:49:45 PM 1001 818504 0.42 2.76 0.00 0 bash
971+
06:49:45 PM 1001 1438525 0.02 0.78 0.00 0 bash
972+
06:49:45 PM 1001 1447221 0.00 0.00 0.00 0 bash
973+
06:49:45 PM 1001 1599497 10.63 16.63 0.03 0 java
974+
06:49:45 PM 1001 2038965 0.00 0.00 0.00 0 bash
975+
06:49:45 PM 1001 2540993 0.00 0.00 0.00 0 bash
976+
```
977+
块 I/O 延迟(iodelay),包括等待同步块 I/O 和换入块 I/O 结束的时间,单位是时钟周期。
978+
979+
除了可以用 pidstat 实时查看,根据 I/O 大小对进程排序,也是性能分析中一个常用的方法。这一点,我推荐另一个工具, iotop。它是一个类似于 top 的工具,你可以按照 I/O大小对进程排序,然后找到 I/O 较大的那些进程。
980+
```bash
981+
$ iotop
982+
Total DISK READ :       0.00 B/s | Total DISK WRITE :       7.85 K/s 
983+
Actual DISK READ:       0.00 B/s | Actual DISK WRITE:       0.00 B/s  
984+
TID  PRIO  USER     DISK READ  DISK WRITE  SWAPIN     IO>    COMMAND 
985+
15055 be/3 root        0.00 B/s    7.85 K/s  0.00 %  0.00 % systemd-journald
986+
```
987+
988+
880989
#### 使用率
881990
#### IOPS
882991
#### 吞吐量

0 commit comments

Comments
 (0)