Linux运维篇-系统io调优

目录

    • 磁盘
    • 文件系统
    • 虚拟文件系统
  • 文件系统的工作原理
  • 文件系统 I/O
    • I/O 的分类
      • 缓冲与非缓冲 I/O
      • 直接与非直接 I/O
      • 阻塞与非阻塞 I/O
      • 同步与异步 I/O
    • 查看文件系统容量
    • 目录项和索引节点缓存
  • 通用块层
  • I/O 栈
  • 磁盘性能指标
  • 磁盘 I/O 观测
  • 进程 I/O 观测
  • I/O瓶颈的排查思路
    • 思路一
    • 思路二
  • I/O优化思路
    • 应用程序优化
    • 文件系统优化
    • 磁盘优化

首先需要介绍两个概念:

磁盘

常见的有机械硬盘(HDD)和固态硬盘(SSD),也有一部分机器会使用NVME协议的固态硬盘,总的来说,磁盘的作用就是持久化存储数据。

  • 机械磁盘的最小读写单位是扇区,一般大小为 512 字节
  • 固态磁盘的最小读写单位是页,通常大小是 4KB、8KB 等

在 Linux 中,磁盘实际上是作为一个块设备来管理的,也就是以块为单位读写数据,并且支持随机读写。每个块设备都会被赋予两个设备号,分别是主、次设备号。主设备号用在驱动程序中,用来区分设备类型;而次设备号则是用来给多个同类设备编号。

文件系统

文件系统是在磁盘之上的树状结构,主要用来管理文件。Linux常见的文件系统有ext4和xfs,这是目前使用最广泛的两种。

虚拟文件系统

为了支持各种不同的文件系统,Linux 内核在用户进程和文件系统的中间,又引入了一个抽象层,也就是虚拟文件系统 VFS(Virtual File System)。

VFS 定义了一组所有文件系统都支持的数据结构和标准接口。这样,用户进程和内核中的其他子系统,只需要跟 VFS 提供的统一接口进行交互就可以了,而不需要再关心底层各种文件系统的实现细节。

备注:

  • lvm技术准确来说是一种磁盘管理技术,在其之上依然有文件系统。
  • 无论机械磁盘,还是固态磁盘,相同磁盘的随机 I/O 都要比连续 I/O 慢很多。对固态磁盘来说,虽然它的随机性能比机械硬盘好很多,但同样存在“先擦除再写入”的限制。随机读写会导致大量的垃圾回收,所以相对应的,随机 I/O 的性能比起连续 I/O 来,也还是差了很多。

此外,连续 I/O 还可以通过预读的方式,来减少 I/O 请求的次数,这也是其性能优异的一个原因。很多性能优化的方案,也都会从这个角度出发,来优化 I/O 性能。

文件系统的工作原理

为了方便管理,Linux 文件系统为每个文件都分配两个数据结构,索引节点(index node)和目录项(directory entry)。它们主要用来记录文件的元信息和目录结构。

索引节点,简称为 inode,用来记录文件的元数据,比如 inode 编号、文件大小、访问权限、修改日期、数据的位置等。索引节点和文件一一对应,它跟文件内容一样,都会被持久化存储到磁盘中。所以记住,索引节点同样占用磁盘空间。

目录项,简称为 dentry,用来记录文件的名字、索引节点指针以及与其他目录项的关联关系。多个关联的目录项,就构成了文件系统的目录结构。不过,不同于索引节点,目录项是由内核维护的一个内存数据结构,所以通常也被叫做目录项缓存。

索引节点是每个文件的唯一标志,而目录项维护的正是文件系统的树状结构。目录项和索引节点的关系是多对一,你可以简单理解为,一个文件可以有多个别名。比如说软链接文件,实际就是多了一个目录项,实际指向的inode还是原来的文件。
在这里插入图片描述
首先,目录项本身就是一个内存缓存,而索引节点则是存储在磁盘中的数据。为了协调慢速磁盘与快速 CPU 的性能差异,文件内容会缓存到页缓存 Cache 中,索引节点也会缓存到内存中,从而提升文件的访问速度。

其次,磁盘在执行文件系统格式化时,会被分成三个存储区域,超级块(Superblock)、索引节点区和数据块区。其中:

  • 超级块,存储整个文件系统的状态
  • 索引节点区,用来存储索引节点
  • 数据块区,则用来存储文件数据

文件系统 I/O

把文件系统挂载到挂载点后,就能通过挂载点,去访问它下面的文件了。VFS 提供了一组标准的文件访问接口。这些接口以系统调用的方式,提供给应用程序使用。

I/O 的分类

文件读写方式的各种差异,导致 I/O 的分类多种多样。

缓冲与非缓冲 I/O

  • 缓冲 I/O,是指利用标准库缓存来加速文件的访问,而标准库内部再通过系统调度访问文件。
  • 非缓冲 I/O,是指直接通过系统调用来访问文件,不再经过标准库缓存。

无论缓冲 I/O 还是非缓冲 I/O,它们最终还是要经过系统调用来访问文件。系统调用后,还会通过页缓存,来减少磁盘的 I/O 操作。

直接与非直接 I/O

  • 直接 I/O,是指跳过操作系统的页缓存,直接跟文件系统交互来访问文件。
  • 非直接 I/O 正好相反,文件读写时,先要经过系统的页缓存,然后再由内核或额外的系统调用,真正写入磁盘。

想要实现直接 I/O,需要你在系统调用中,指定 O_DIRECT 标志。如果没有设置过,默认的是非直接 I/O。不过要注意,直接 I/O、非直接 I/O,本质上还是和文件系统交互。如果是在数据库等场景中,你还会看到,跳过文件系统读写磁盘的情况,也就是我们通常所说的裸 I/O。

阻塞与非阻塞 I/O

  • 阻塞 I/O,是指应用程序执行 I/O 操作后,如果没有获得响应,就会阻塞当前线程,自然就不能执行其他任务。
  • 非阻塞 I/O,是指应用程序执行 I/O 操作后,不会阻塞当前的线程,可以继续执行其他的任务,随后
    再通过轮询或者事件通知的形式,获取调用的结果。

例如,访问管道或者网络套接字时,设置 O_NONBLOCK 标志,就表示用非阻塞方式访问;而如果不做任何设置,默认的就是阻塞访问。

同步与异步 I/O

  • 同步 I/O,是指应用程序执行 I/O 操作后,要一直等到整个 I/O 完成后,才能获得 I/O 响应。
  • 异步 I/O,是指应用程序执行 I/O 操作后,不用等待完成和完成后的响应,而是继续执行就可以。等到这次 I/O 完成后,响应会用事件通知的方式,反馈给应用程序。

例如,在访问管道或者网络套接字时,设置了 O_ASYNC 选项后,相应的 I/O 就是异步 I/O。这样,内核会再通过 SIGIO 或者 SIGPOLL,来通知进程文件是否可读写。

查看文件系统容量

文件系统和磁盘空间:

df -h[root@localhost ~]# df -h
Filesystem               Size  Used Avail Use% Mounted on
devtmpfs                 1.9G     0  1.9G   0% /dev
tmpfs                    1.9G  1.1M  1.9G   1% /dev/shm
tmpfs                    1.9G   12M  1.9G   1% /run
tmpfs                    1.9G     0  1.9G   0% /sys/fs/cgroup
/dev/mapper/centos-root   41G  6.8G   35G  17% /
/dev/sda2               1014M  153M  862M  16% /boot
tmpfs                    378M     0  378M   0% /run/user/0

指定具体的目录或挂载点:

df -h /[root@localhost ~]# df -h /
Filesystem               Size  Used Avail Use% Mounted on
/dev/mapper/centos-root   41G  6.8G   35G  17% /

索引节点的容量:

df -hi[root@localhost ~]# df -hi
Filesystem              Inodes IUsed IFree IUse% Mounted on
devtmpfs                  469K   398  469K    1% /dev
tmpfs                     472K     3  472K    1% /dev/shm
tmpfs                     472K  1.3K  471K    1% /run
tmpfs                     472K    16  472K    1% /sys/fs/cgroup
/dev/mapper/centos-root    21M   70K   21M    1% /
/dev/sda2                 512K   327  512K    1% /boot
tmpfs                     472K     1  472K    1% /run/user/0

当发现索引节点空间不足,但磁盘空间充足时,很可能就是过多小文件导致的。一般来说,删除这些小文件,或者把它们移动到索引节点充足的其他磁盘中,就可以解决这个问题。

目录项和索引节点缓存

[root@localhost ~]# cat /proc/slabinfo | grep -E '^#|dentry|inode'
# name            <active_objs> <num_objs> <objsize> <objperslab> <pagesperslab> : tunables <limit> <batchcount> <sharedfactor> : slabdata <active_slabs> <num_slabs> <sharedavail>
xfs_inode          27540  27540    960   34    8 : tunables    0    0    0 : slabdata    810    810      0
fuse_inode             0      0    768   42    8 : tunables    0    0    0 : slabdata      0      0      0
mqueue_inode_cache     36     36    896   36    8 : tunables    0    0    0 : slabdata      1      1      0
hugetlbfs_inode_cache     53     53    608   53    8 : tunables    0    0    0 : slabdata      1      1      0
sock_inode_cache    1071   1071    640   51    8 : tunables    0    0    0 : slabdata     21     21      0
shmem_inode_cache   1824   1824    680   48    8 : tunables    0    0    0 : slabdata     38     38      0
proc_inode_cache   15200  15696    672   48    8 : tunables    0    0    0 : slabdata    327    327      0
inode_cache        17380  17380    592   55    8 : tunables    0    0    0 : slabdata    316    316      0
dentry             62244  62244    192   42    2 : tunables    0    0    0 : slabdata   1482   1482      0
selinux_inode_security  30804  30804     40  102    1 : tunables    0    0    0 : slabdata    302    302      0

dentry 行表示目录项缓存,inode_cache 行,表示 VFS 索引节点缓存,其余的则是各种文件系统的索引节点缓存。
也可以用 slabtop 来查看:

[root@localhost ~]# slabtopActive / Total Objects (% used)    : 934307 / 1011266 (92.4%)Active / Total Slabs (% used)      : 22810 / 22810 (100.0%)Active / Total Caches (% used)     : 74 / 106 (69.8%)Active / Total Size (% used)       : 175731.83K / 188576.36K (93.2%)Minimum / Average / Maximum Object : 0.01K / 0.19K / 8.00KOBJS ACTIVE  USE OBJ SIZE  SLABS OBJ/SLAB CACHE SIZE NAME
582153 515278  88%    0.10K  14927       39     59708K buffer_head62244  62244 100%    0.19K   1482       42     11856K dentry46988  46988 100%    0.12K    691       68      5528K kernfs_node_cache32512  32371  99%    0.06K    508       64      2032K kmalloc-6430804  30804 100%    0.04K    302      102      1208K selinux_inode_security28952  28952 100%    0.57K    517       56     16544K radix_tree_node27540  27540 100%    0.94K    810       34     25920K xfs_inode26880  26880 100%    0.02K    105      256       420K kmalloc-1623414  23414 100%    0.17K    509       46      4072K xfs_ili17380  17380 100%    0.58K    316       55     10112K inode_cache15696  15200  96%    0.66K    327       48     10464K proc_inode_cache14048  12400  88%    1.00K    439       32     14048K kmalloc-102410880  10880 100%    0.05K    128       85       512K shared_policy_node10624  10624 100%    0.03K     83      128       332K kmalloc-3210304  10304 100%    0.07K    184       56       736K avc_node10240  10240 100%    0.01K     20      512        80K kmalloc-88904   8611  96%    0.19K    212       42      1696K kmalloc-1928064   7067  87%    0.25K    126       64      2016K kmalloc-2566919   6632  95%    0.21K    187       37      1496K vm_area_struct10688   5789  54%    0.50K    167       64      5344K kmalloc-5123108   3108 100%    0.38K     74       42      1184K mnt_cache2772   2772 100%    0.09K     66       42       264K kmalloc-963009   2533  84%    0.08K     59       51       236K anon_vma2816   2445  86%    0.12K     44       64       352K kmalloc-1281824   1824 100%    0.66K     38       48      1216K shmem_inode_cache1664   1548  93%    2.00K    104       16      3328K kmalloc-20481071   1071 100%    0.62K     21       51       672K sock_inode_cache672    672 100%    0.19K     16       42       128K cred_jar612    612 100%    0.31K     12       51       192K bio-3572    572 100%    0.18K     13       44       104K xfs_log_ticket555    555 100%    0.21K     15       37       120K xfs_btree_cur570    418  73%    0.41K     15       38       240K xfs_efd_item396    396 100%    0.11K     11       36        44K task_delay_info

通用块层

跟虚拟文件系统 VFS 类似,为了减小不同块设备的差异带来的影响,Linux 通过一个统一的通用块层,来管理各种不同的块设备。

通用块层,其实是处在文件系统和磁盘驱动中间的一个块设备抽象层。它主要有两个功能 :

  • 第一个功能
    跟虚拟文件系统的功能类似。向上,为文件系统和应用程序,提供访问块设备的标准接口;
    向下,把各种异构的磁盘设备抽象为统一的块设备,并提供统一框架来管理这些设备的驱动程序。
  • 第二个功能
    通用块层还会给文件系统和应用程序发来的 I/O 请求排队,并通过重新排序、请求合并等方式,提高磁盘读写的效率。

其中,对 I/O 请求排序的过程,也就是我们熟悉的 I/O 调度。事实上,Linux 内核支持四种 I/O 调度算法,分别是

  • NONE
    更确切来说,并不能算 I/O 调度算法。因为它完全不使用任何 I/O 调度器,对文件系统和应用程序的 I/O 其实不做任何处理,常用在虚拟机中(此时磁盘 I/O 调度完全由物理机负责)。
  • NOOP
    是最简单的一种 I/O 调度算法。它实际上是一个先入先出的队列,只做一些最基本的请求合并,常用于 SSD 磁盘。
  • CFQ
    也被称为完全公平调度器,是现在很多发行版的默认 I/O 调度器,它为每个进程维护了一个 I/O 调度队列,并按照时间片来均匀分布每个进程的 I/O 请求。类似于进程 CPU 调度,CFQ 还支持进程 I/O 的优先级调度,所以它适用于运行大量进程的系统,像是桌面环境、多媒体应用等。
  • DeadLine。
    分别为读、写请求创建了不同的 I/O 队列,可以提高机械磁盘的吞吐量,并确保达到最终期限(deadline)的请求被优先处理。DeadLine 调度算法,多用在 I/O 压力比较重的场景,比如数据库等。

I/O 栈

我们可以把 Linux 存储系统的 I/O 栈,由上到下分为三个层次,分别是文件系统层、通用块层和设备层。这三个 I/O 层的关系如下图所示,这其实也是 Linux 存储系统的 I/O 栈全景图。以Linux kernel-6.2为例:

在这里插入图片描述
根据这张 I/O 栈的全景图,我们可以更清楚地理解,存储系统 I/O 的工作原理。

  • 文件系统层:包括虚拟文件系统和其他各种文件系统的具体实现。它为上层的应用程序,提供标准的文件访问接口;对下会通过通用块层,来存储和管理磁盘数据。
  • 通用块层:包括块设备 I/O 队列和 I/O 调度器。它会对文件系统的 I/O 请求进行排队,再通过重新排序和请求合并,然后才要发送给下一级的设备层。
  • 设备层:包括存储设备和相应的驱动程序,负责最终物理设备的 I/O 操作。
    存储系统的 I/O ,通常是整个系统中最慢的一环。所以, Linux 通过多种缓存机制来优化 I/O 效率。

例如,为了优化文件访问的性能,会使用页缓存、索引节点缓存、目录项缓存等多种缓存机制,以减少对下层块设备的直接调用。同样,为了优化块设备的访问效率,会使用缓冲区,来缓存块设备的数据。

磁盘性能指标

磁盘性能的衡量标准有使用率、饱和度、IOPS、吞吐量以及响应时间等。这五个指标,是衡量磁盘性能的基本指标。

  • 使用率:是指磁盘处理 I/O 的时间百分比。过高的使用率(比如超过 80%),通常意味着磁盘 I/O 存在性能瓶颈。
  • 饱和度:是指磁盘处理 I/O 的繁忙程度。过高的饱和度,意味着磁盘存在严重的性能瓶颈。当饱和度为 100% 时,磁盘无法接受新的 I/O 请求。
  • IOPS(Input/Output Per Second):是指每秒的 I/O 请求数。
  • 吞吐量:是指每秒的 I/O 请求大小。
  • 响应时间:是指 I/O 请求从发出到收到响应的间隔时间。

要注意的是,使用率只考虑有没有 I/O,而不考虑 I/O 的大小。换句话说,当使用率是 100% 的时候,磁盘依然有可能接受新的 I/O 请求。

在数据库、大量小文件等这类随机读写比较多的场景中,IOPS 更能反映系统的整体性能;而在多媒体等顺序读写较多的场景中,吞吐量才更能反映系统的整体性能。

磁盘 I/O 观测

iostat 是最常用的磁盘 I/O 性能观测工具,它来自于sysstat这个工具包,它提供了每个磁盘的使用率、IOPS、吞吐量等各种常见的性能指标,当然,这些指标实际上来自 /proc/diskstats。

[root@localhost ~]# iostat -d -x
Linux 3.10.0-1160.71.1.el7.x86_64 (localhost.localdomain)       03/24/2025      _x86_64_        (2 CPU)Device:         rrqm/s   wrqm/s     r/s     w/s    rkB/s    wkB/s avgrq-sz avgqu-sz   await r_await w_await  svctm  %util
scd0              0.00     0.00    0.00    0.00     0.01     0.00   114.22     0.00    1.50    1.50    0.00   1.17   0.00
sda               0.00     0.03    0.37    0.43     7.11    55.92   156.61     0.00    0.33    0.38    0.29   0.10   0.01
dm-0              0.00     0.00    0.35    0.46     6.69    55.89   155.56     0.00    0.43    0.41    0.45   0.10   0.01
dm-1              0.00     0.00    0.00    0.00     0.03     0.01    24.17     0.00    0.66    0.15    1.04   0.22   0.00

这些指标中,需要注意:

  • %util :就是我们前面提到的磁盘 I/O 使用率;
  • r/s + w/s :就是 IOPS;
  • rkB/s+wkB/s :就是吞吐量;
  • r_await + w_await :就是响应时间。

在观测指标时,结合请求的大小( rareq-sz 和 wareq-sz)一起分析。

进程 I/O 观测

除了每块磁盘的 I/O 情况,每个进程的 I/O 情况也是我们需要关注的重点。

上面提到的 iostat 只提供磁盘整体的 I/O 性能数据,缺点在于,并不能知道具体是哪些进程在进行磁盘读写。要观察进程的 I/O 情况,你还可以使用 pidstat 和 iotop 这两个工具。

给 pidstat 加上 -d 参数,你就可以看到进程的 I/O 情况:

[root@localhost ~]# pidstat -d
Linux 3.10.0-1160.71.1.el7.x86_64 (localhost.localdomain)       03/24/2025      _x86_64_        (2 CPU)11:03:46 PM   UID       PID   kB_rd/s   kB_wr/s kB_ccwr/s  Command
11:03:46 PM     0         1      0.92     13.55      0.01  systemd
11:03:46 PM     0        47      0.00      0.00      0.00  kworker/u256:1
11:03:46 PM     0       415      0.00      0.00      0.00  xfsaild/dm-0
11:03:46 PM     0       496      0.01      0.00      0.00  systemd-journal
11:03:46 PM     0       519      0.18      0.00      0.00  systemd-udevd
11:03:46 PM     0       525      0.00      0.00      0.00  lvmetad
11:03:46 PM     0       652      0.00      0.01      0.00  auditd
11:03:46 PM     0       674      0.01      0.00      0.00  systemd-logind
11:03:46 PM    81       675      0.01      0.00      0.00  dbus-daemon
11:03:46 PM     0       677      0.08      0.00      0.00  NetworkManager
11:03:46 PM     0       680      0.00      0.00      0.00  irqbalance
11:03:46 PM     0       681      0.07      0.00      0.00  VGAuthService
11:03:46 PM     0       682      0.04      0.00      0.00  vmtoolsd
11:03:46 PM   999       684      0.07      0.00      0.00  polkitd
11:03:46 PM     0       687      0.01      0.00      0.00  crond
11:03:46 PM     0       690      0.00      0.00      0.00  agetty
11:03:46 PM     0       943      0.11      0.00      0.00  tuned
11:03:46 PM     0       944      0.01      0.00      0.00  sshd
11:03:46 PM     0       947      0.01      0.02      0.01  rsyslogd
11:03:46 PM    26       965      0.13      0.01      0.00  postmaster
11:03:46 PM    26      1004      0.00      0.00      0.00  postmaster
11:03:46 PM    26      1008      0.00      0.00      0.00  postmaster
11:03:46 PM    26      1009      0.00      0.00      0.00  postmaster
11:03:46 PM    26      1014      0.00      0.00      0.00  postmaster
11:03:46 PM    26      1015      0.00      0.00      0.00  postmaster
11:03:46 PM    26      1016      0.00      0.00      0.00  postmaster
11:03:46 PM     0      1150      0.05      0.00      0.00  master
11:03:46 PM    89      1154      0.00      0.00      0.00  qmgr
11:03:46 PM     0      1444      0.03      0.00      0.00  sshd
11:03:46 PM     0      1446      0.01      0.00      0.00  sshd
11:03:46 PM     0      1448      3.81     40.34      0.06  bash
11:03:46 PM     0      1463      0.00      0.00      0.00  sftp-server
11:03:46 PM     0      1909      0.06      0.00      0.00  sshd
11:03:46 PM     0      1912      0.01      0.00      0.00  sshd
11:03:46 PM     0      1914      1.38      0.93      0.01  bash
11:03:46 PM     0      1929      0.00      0.00      0.00  sftp-server
11:03:46 PM     0      6466      0.00      0.00      0.00  su
11:03:46 PM  1000      6468      0.00      0.00      0.00  bash

从 pidstat 的输出你能看到,它可以实时查看每个进程的 I/O 情况,包括下面这些内容:

  • 用户 ID(UID)和进程 ID(PID) 。
  • 每秒读取的数据大小(kB_rd/s) ,单位是 KB。
  • 每秒发出的写请求数据大小(kB_wr/s) ,单位是 KB。
  • 每秒取消的写请求数据大小(kB_ccwr/s) ,单位是 KB。
  • 块 I/O 延迟(iodelay),包括等待同步块 I/O 和换入块 I/O 结束的时间,单位是时钟周期。

除了可以用 pidstat 实时查看,根据 I/O 大小对进程排序,也是性能分析中一个常用的方法,可以用 iotop。iotop 是一个类似于 top 的工具,你可以按照 I/O 大小对进程排序,然后找到 I/O 较大的那些进程。

[root@localhost ~]# iotop
Total DISK READ :       0.00 B/s | Total DISK WRITE :       0.00 B/s
Actual DISK READ:       0.00 B/s | Actual DISK WRITE:       0.00 B/sTID  PRIO  USER     DISK READ  DISK WRITE  SWAPIN     IO>    COMMAND30 be/4 root        0.00 B/s    0.00 B/s  0.00 %  0.02 % [kworker/1:1]1 be/4 root        0.00 B/s    0.00 B/s  0.00 %  0.00 % systemd --switched-root --system --deserialize 222 be/4 root        0.00 B/s    0.00 B/s  0.00 %  0.00 % [kthreadd]4 be/0 root        0.00 B/s    0.00 B/s  0.00 %  0.00 % [kworker/0:0H]6 be/4 root        0.00 B/s    0.00 B/s  0.00 %  0.00 % [ksoftirqd/0]7 rt/4 root        0.00 B/s    0.00 B/s  0.00 %  0.00 % [migration/0]8 be/4 root        0.00 B/s    0.00 B/s  0.00 %  0.00 % [rcu_bh]9 be/4 root        0.00 B/s    0.00 B/s  0.00 %  0.00 % [rcu_sched]10 be/0 root        0.00 B/s    0.00 B/s  0.00 %  0.00 % [lru-add-drain]11 rt/4 root        0.00 B/s    0.00 B/s  0.00 %  0.00 % [watchdog/0]12 rt/4 root        0.00 B/s    0.00 B/s  0.00 %  0.00 % [watchdog/1]13 rt/4 root        0.00 B/s    0.00 B/s  0.00 %  0.00 % [migration/1]14 be/4 root        0.00 B/s    0.00 B/s  0.00 %  0.00 % [ksoftirqd/1]16 be/0 root        0.00 B/s    0.00 B/s  0.00 %  0.00 % [kworker/1:0H]18 be/4 root        0.00 B/s    0.00 B/s  0.00 %  0.00 % [kdevtmpfs]19 be/0 root        0.00 B/s    0.00 B/s  0.00 %  0.00 % [netns]20 be/4 root        0.00 B/s    0.00 B/s  0.00 %  0.00 % [khungtaskd]21 be/0 root        0.00 B/s    0.00 B/s  0.00 %  0.00 % [writeback]22 be/0 root        0.00 B/s    0.00 B/s  0.00 %  0.00 % [kintegrityd]23 be/0 root        0.00 B/s    0.00 B/s  0.00 %  0.00 % [bioset]24 be/0 root        0.00 B/s    0.00 B/s  0.00 %  0.00 % [bioset]25 be/0 root        0.00 B/s    0.00 B/s  0.00 %  0.00 % [bioset]26 be/0 root        0.00 B/s    0.00 B/s  0.00 %  0.00 % [kblockd]27 be/0 root        0.00 B/s    0.00 B/s  0.00 %  0.00 % [md]28 be/0 root        0.00 B/s    0.00 B/s  0.00 %  0.00 % [edac-poller]29 be/0 root        0.00 B/s    0.00 B/s  0.00 %  0.00 % [watchdogd]35 be/4 root        0.00 B/s    0.00 B/s  0.00 %  0.00 % [kswapd0]36 be/5 root        0.00 B/s    0.00 B/s  0.00 %  0.00 % [ksmd]37 be/7 root        0.00 B/s    0.00 B/s  0.00 %  0.00 % [khugepaged]38 be/0 root        0.00 B/s    0.00 B/s  0.00 %  0.00 % [crypto]519 be/4 root        0.00 B/s    0.00 B/s  0.00 %  0.00 % systemd-udevd46 be/0 root        0.00 B/s    0.00 B/s  0.00 %  0.00 % [kthrotld]47 be/4 root        0.00 B/s    0.00 B/s  0.00 %  0.00 % [kworker/u256:1]48 be/0 root        0.00 B/s    0.00 B/s  0.00 %  0.00 % [kmpath_rdacd]49 be/0 root        0.00 B/s    0.00 B/s  0.00 %  0.00 % [kaluad]51 be/0 root        0.00 B/s    0.00 B/s  0.00 %  0.00 % [kpsmoused]53 be/0 root        0.00 B/s    0.00 B/s  0.00 %  0.00 % [ipv6_addrconf]

从这个输出可以看到,前两行分别表示,进程的磁盘读写大小总数和磁盘真实的读写大小总数。因为缓存、缓冲区、I/O 合并等因素的影响,它们可能并不相等。剩下的部分,则是从各个角度来分别表示进程的 I/O 情况,包括线程 ID、I/O 优先级、每秒读磁盘的大小、每秒写磁盘的大小、换入和等待 I/O 的时钟百分比等。

I/O瓶颈的排查思路

思路一

先用 top ,来观察 CPU 和内存的使用情况;
再用 iostat ,来观察磁盘的 I/O 情况。
再用 pidstat ,观察进程的 I/O 情况。
最后用 strace 进行具体的跟踪。

思路二

先用 iostat 发现磁盘 I/O 性能瓶颈;
再借助 pidstat ,定位出导致瓶颈的进程;
随后分析进程的 I/O 行为;
最后,结合应用程序的原理,分析这些 I/O 的来源。

I/O优化思路

应用程序优化

  • 可以用追加写代替随机写,减少寻址开销,加快 I/O 写的速度。
  • 可以借助缓存 I/O ,充分利用系统缓存,降低实际 I/O 的次数。
  • 可以在应用程序内部构建自己的缓存,或者用 Redis 这类外部缓存系统。
    这样,一方面,能在应用程序内部,控制缓存的数据和生命周期;另一方面,也能降低其他应用程序使用缓存对自身的影响。
  • 在需要频繁读写同一块磁盘空间时,可以用 mmap 代替 read/write,减少内存的拷贝次数。
  • 在需要同步写的场景中,尽量将写请求合并,而不是让每个请求都同步写入磁盘,即可以用 fsync() 取代 O_SYNC。
  • 在多个应用程序共享相同磁盘时,为了保证 I/O 不被某个应用完全占用,推荐使用 cgroups 的 I/O 子系统,来限制进程 / 进程组的 IOPS 以及吞吐量。
  • 在使用 CFQ 调度器时,可以用 ionice 来调整进程的 I/O 调度优先级,特别是提高核心应用的 I/O 优先级。
    ionice 支持三个优先级类:Idle、Best-effort 和 Realtime。其中, Best-effort 和 Realtime 还分别支持 0-7 的级别,数值越小,则表示优先级别越高。

文件系统优化

  • 你可以根据实际负载场景的不同,选择最适合的文件系统。比如 Ubuntu 默认使用 ext4 文件系统,而 CentOS 7 默认使用 xfs 文件系统。
  • 在选好文件系统后,还可以进一步优化文件系统的配置选项,包括文件系统的特性(如 ext_attr、dir_index)、日志模式(如 journal、ordered、writeback)、挂载选项(如 noatime)等等。
  • 可以优化文件系统的缓存。比如,你可以优化 pdflush 脏页的刷新频率(比如设置 dirty_expire_centisecs 和 dirty_writeback_centisecs)以及脏页的限额(比如调整 dirty_background_ratio 和 dirty_ratio 等)。
  • 在不需要持久化时,你还可以用内存文件系统 tmpfs,以获得更好的 I/O 性能 。
    tmpfs 把数据直接保存在内存中,而不是磁盘中。比如 /dev/shm/ ,就是大多数 Linux 默认配置的一个内存文件系统,它的大小默认为总内存的一半。

磁盘优化

  • 最简单有效的优化方法,就是换用性能更好的磁盘,比如用 SSD 替代 HDD。

  • 我们可以使用 RAID ,把多块磁盘组合成一个逻辑磁盘,构成冗余独立磁盘阵列。这样做既可以提高数据的可靠性,又可以提升数据的访问性能。

  • 针对磁盘和应用程序 I/O 模式的特征,我们可以选择最适合的 I/O 调度算法。比方说,SSD 和虚拟机中的磁盘,通常用的是 noop 调度算法。而数据库应用,我更推荐使用 deadline 算法。

  • 我们可以对应用程序的数据,进行磁盘级别的隔离。比如,我们可以为日志、数据库等 I/O 压力比较重的应用,配置单独的磁盘。

  • 在顺序读比较多的场景中,我们可以增大磁盘的预读数据,比如,你可以通过下面两种方法,调整 /dev/sdb 的预读大小。

    调整内核选项 /sys/block/sdb/queue/read_ahead_kb,默认大小是 128 KB,单位为 KB

    使用 blockdev 工具设置,比如 blockdev --setra 8192 /dev/sdb
    注意这里的单位是 512B(0.5KB),所以它的数值总是 read_ahead_kb 的两倍

  • 我们可以优化内核块设备 I/O 的选项。比如,可以调整磁盘队列的长度 /sys/block/sdb/queue/nr_requests,适当增大队列长度,可以提升磁盘的吞吐量(当然也会导致 I/O 延迟增大)。

  • 磁盘本身出现硬件错误,也会导致 I/O 性能急剧下降,所以发现磁盘性能急剧下降时,还需要确认,磁盘本身是不是出现了硬件错误。比如,你可以查看 dmesg 中是否有硬件 I/O 故障的日志。 还可以使用 badblocks、smartctl 等工具,检测磁盘的硬件问题,或用 e2fsck 等来检测文件系统的错误。如果发现问题,你可以使用 fsck 等工具来修复。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/898936.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

C语言笔记(鹏哥)上课板书+课件汇总(动态内存管理)--数据结构常用

动态内存管理 引言&#xff1a;将内存升起一段空间存放数据有几种手段 创建变量&#xff1a;存放一个值创建数组&#xff1a;存放多个连续的一组值 以上开辟的内存空间是固定的&#xff0c;创建大了&#xff0c;空间浪费&#xff0c;创建小了&#xff0c;空间不够。并且一旦…

uv - Getting Started 开始使用 [官方文档翻译]

文章目录 uv亮点安装项目脚本工具Python 版本pip 接口了解更多 入门安装 uv安装方法独立安装程序PyPICargoHomebrewWinGetScoopDockerGitHub 发布 升级 uvShell 自动补全卸载 第一次使用 uv特性Python 版本脚本项目工具pip 接口实用工具 获取帮助帮助菜单查看版本故障排除问题在…

HarmonyOS Next~鸿蒙系统安全:构建全方位的防护体系

HarmonyOS Next&#xff5e;鸿蒙系统安全&#xff1a;构建全方位的防护体系 ​ ​ 在数字化飞速发展的当下&#xff0c;操作系统的安全性成为了用户和开发者关注的焦点。华为鸿蒙系统&#xff08;HarmonyOS&#xff09;以其独特的架构和强大的安全性能&#xff0c;在众多操作…

本地安装deepseek大模型,并使用 python 调用

首先进入 ollama 官网 https://ollama.com/点击下载 下载完成后所有都是下一步&#xff0c;就可以 点击搜索 Models &#xff1a; https://ollama.com/search然后点击下载&#xff1a; 选择后复制: ollama run deepseek-r1:32b例如&#xff1a; 让它安装完成后&#xff1…

Linux wifi driver 注册和设备探测流程

基础流程 wifi驱动加载&#xff08;insmod或者modprobe&#xff09; 设备驱动匹配探测&#xff08;我们常见的probe函数&#xff09; 整体流程 驱动加载 → 注册支持设备 → 设备插入 → 匹配驱动 → 初始化硬件 → 创建网络接口 明确两点 两个流程 驱动加载&#xf…

【机器人】复现 GrainGrasp 精细指导的灵巧手抓取

GrainGrasp为每个手指提供细粒度的接触指导&#xff0c;为灵巧手生成精细的抓取策略。 通过单独调整每个手指的接触来实现更稳定的抓取&#xff0c;从而提供了更接近人类能力的抓取指导。 论文地址&#xff1a;GrainGrasp: Dexterous Grasp Generation with Fine-grained Con…

快速部署Samba共享服务器作为k8s后端存储

由于Ceph Squid&#xff08;v19.2.1&#xff09;‌不原生支持直接导出 SMB 服务器‌&#xff0c;需通过手动集成 Samba 或其他第三方工具实现‌ 所以直接部署最简单的 安装软件包 apt install samba编辑配置文件 vim /etc/samba/smb.conf在最末尾添加以下 # cp /etc/samba/sm…

【时时三省】(C语言基础)选择结构和条件判断

山不在高,有仙则名。水不在深,有龙则灵。 ----CSDN 时时三省 选择结构和条件判断 在现实生活中需要进行判断和选择的情况是很多的。如:从北京出发上高速公路,到一个岔路口,有两个出口,一个是去上海方向,另一个是沈阳方向。驾车者到此处必须进行判断,根据自己的目的地…

【MYSQL】索引和事务

&#x1f970;&#x1f970;&#x1f970;来都来了&#xff0c;不妨点个关注叭&#xff01; &#x1f449;博客主页&#xff1a;欢迎各位大佬!&#x1f448; 本期内容讲解 MySQL 中的索引和事务&#xff0c;在学习的过程中&#xff0c;我们需要经常问自己为什么 文章目录 1. 索…

计划管理工具应该具备的能(甘特图)

在当今快节奏的项目管理环境中&#xff0c;高效地规划和跟踪项目进度是至关重要的。甘特图&#xff0c;作为项目管理领域的经典工具&#xff0c;以其直观的时间轴和任务分配方式&#xff0c;深受项目管理者的青睐。 随着数字化时代的到来&#xff0c;甘特图线上编辑器应运而生&…

Redis分布式寻址算法

分布式寻址算法是分布式系统中用于确定数据应该存储在哪个节点的算法。这些算法对于实现高效的数据存取、负载均衡和系统扩展性至关重要。以下是几种常见的分布式寻址算法的解释&#xff1a; 1. Hash 算法 原理&#xff1a;通过哈希函数将数据的键&#xff08;Key&#xff09…

CSS动画

目录 一、核心概念与语法 1. keyframes 关键帧 2. animation 属性 二、动画调速函数&#xff08;animation-timing-function&#xff09; 1. 预设值 2. 贝塞尔曲线 3. 步进函数&#xff08;steps()&#xff09; 三、动画控制与交互 1. 暂停与恢复 2. JavaScript 控制…

2025年河北省第二届职业技能大赛网络安全项目 模块 B样题任务书

2025年河北省第二届职业技能大赛网络安全项目 模块 B样题任务书 河北省第二届职业技能大赛网络安全项目-模块 B-夺旗挑战赛&#xff08;CTF&#xff09;一、目标系统1二、目标系统2三、目标系统3四、目标系统4 需要真题环境-培训可以私信博主&#xff01; 河北省第二届职业技能…

钞票准备好了吗?鸿蒙电脑 5 月见

3月20日&#xff0c;在华为 Pura 先锋盛典及鸿蒙智行新品发布会上&#xff0c;华为常务董事、终端BG董事长、智能汽车解决方案BU董事长余承东表示&#xff0c;华为终端全面进入鸿蒙时代&#xff0c;今年5月将推出鸿蒙电脑。 在3月20日的华为Pura先锋盛典及鸿蒙智行新品发布会上…

Java高频面试之集合-15

hello啊&#xff0c;各位观众姥爷们&#xff01;&#xff01;&#xff01;本baby今天来报道了&#xff01;哈哈哈哈哈嗝&#x1f436; 面试官&#xff1a;解决哈希冲突有哪些方法&#xff1f; 1. 开放寻址法&#xff08;Open Addressing&#xff09; 核心思想&#xff1a;当哈…

【机器学习】建模流程

1、数据获取 1.1 来源 数据获取是机器学习建模的第一步&#xff0c;常见的数据来源包括数据库、API、网络爬虫等。 数据库是企业内部常见的数据存储方式&#xff0c;例如&#xff1a;MySQL、Oracle等关系型数据库&#xff0c;以及MongoDB等非关系型数据库&#xff0c;它们能够…

GitHub 上的 Khoj 项目:打造你的专属 AI 第二大脑

在信息爆炸的时代&#xff0c;高效管理和利用个人知识变得愈发重要。GitHub 上的 Khoj 项目为我们提供了一个强大的解决方案&#xff0c;它能成为你的 “AI 第二大脑”&#xff0c;帮你轻松整合、搜索和运用知识。今天&#xff0c;就来详细了解下 Khoj。​ Khoj 是什么&#x…

爬虫(requsets)笔记

一、request_基本使用 pip install requests -i https://pypi.douban.com/simple 一个类型六个属性 r.text 获取网站源码 r.encoding 访问或定制编码方式r.url 获取请求的urlr.content 响应的字节类型r.status_code 响应的状态码r.headers 响应的头信息 import requestsur…

centos7连不上接网络

选择编辑&#xff0c; 选择虚拟机网络编辑 右键虚拟机&#xff0c;点击设置&#xff0c;设置网络,选择nat模式&#xff0c; 配置&#xff1a;/etc/sysconfig/network-scripts/ifcfg-ens33 vim /etc/sysconfig/network-scripts/ifcfg-ens33设置IP地址如图所示&#xff0c;重…

OpenResty(Lua)+Redis实现动态封禁IP

文章目录 架构设计环境准备源码编辑安装OpenResty下载安装准备依赖编译安装配置环境变量&#xff08;可选&#xff09;OpenResty 服务管理命令 安装Redis配置Lua脚本测试准备测试工具测试封禁逻辑 删除版本信息清除编译安装的OpenResty 架构设计 通过 Nginx Redis 的方案&…