16
2025
01
17:01:19

聊一聊被众人误解许久的 iowait

1了解 Linux IOWait

我见过许多 Linux 性能工程师将 CPU 使用率中的 "IOWait" 部分看作是表明系统何时受到 I/O 限制

的东西。在这篇博客中,我将解释为什么这种方法不可靠以及可以使用哪些更好的指标。

让我们从运行一个小实验开始——在系统上产生大量的 I/O 使用:

sysbench  --threads=8 --time=0 --max-requests=0  fileio --file-num=1 --file-total-size=10G --file-io-mode=sync --file-extra-flags=direct --file-test-mode=rndrd run

Percona 监控和管理 (PMM) 中的 CPU 使用情况:

root@iotest:~# vmstat 10
procs -----------memory---------- ---swap-- -----io---- -system-- ------cpu-----
 r  b   swpd   free   buff  cache   si   so    bi    bo   in   cs us sy id wa st
 3  6      0 7137152  26452 762972    0    0 40500  1714 2519 4693  1  6 55 35  3
 2  8      0 7138100  26476 762964    0    0 344971    17 20059 37865  3 13  7 73  5
 0  8      0 7139160  26500 763016    0    0 347448    37 20599 37935  4 17  5 72  3
 2  7      0 7139736  26524 762968    0    0 334730    14 19190 36256  3 15  4 71  6
 4  4      0 7139484  26536 762900    0    0 253995     6 15230 27934  2 11  6 77  4
 0  7      0 7139484  26536 762900    0    0 350854     6 20777 38345  2 13  3 77  5

到目前为止,一切顺利,而且——我们看到 I/O 密集型工作负载明显对应于高 IOWait(vmstat 中的 "wa" 列)。

让我们继续运行我们的 I/O 密集型工作负载并添加一个繁重的 CPU 密集型工作负载:

sysbench --threads=8 --time=0 cpu run

root@iotest:~# vmstat 10
procs -----------memory---------- ---swap-- -----io---- -system-- ------cpu-----
 r  b   swpd   free   buff  cache   si   so    bi    bo   in   cs us sy id wa st
12  4      0 7121640  26832 763476    0    0 48034  1460 2895 5443  6  7 47 37  3
13  3      0 7120416  26856 763464    0    0 256464    14 12404 25937 69 15  0  0 16
 8  8      0 7121020  26880 763496    0    0 325789    16 15788 33383 85 15  0  0  0
10  6      0 7121464  26904 763460    0    0 322954    33 16025 33461 83 15  0  0  1
 9  7      0 7123592  26928 763524    0    0 336794    14 16772 34907 85 15  0  0  1
13  3      0 7124132  26940 763556    0    0 386384    10 17704 38679 84 16  0  0  0
 9  7      0 7128252  26964 763604    0    0 356198    13 16303 35275 84 15  0  0  0
 9  7      0 7128052  26988 763584    0    0 324723    14 13905 30898 80 15  0  0  5
10  6      0 7122020  27012 763584    0    0 380429    16 16770 37079 81 18  0  0  1

发生了什么?IOWait 完全消失了,现在这个系统看起来完全不受 I/O 限制了!

当然,实际上,我们的第一个工作负载没有任何变化——它仍然是 I/O 密集型的;当我们查看 "IOWait" 时,它就变得不可见了!

要理解发生了什么,我们真的需要了解 "IOWait" 是什么以及它是如何计算的。

有一篇很好的文章(译文在后面)对这个主题进行了更详细的介绍,但基本上,"IOWait" 是一种空闲 CPU 时间。如果 CPU 核心因为没有工作要做而空闲,则该时间被计为 "idle"。但是,如果它因为某个进程在磁盘上等待而空闲,则 I/O 时间将计入"IOWait"。

但是,如果一个进程正在等待磁盘 I/O 但系统上的其他进程可以使用 CPU,则该时间将作为用户态/系统态时间计入到它们的 CPU 使用率。

由于这种计算方式,其他有趣的行为是可能的。现在我们不再运行八个 I/O 密集型线程,而是在四核 VM 上运行一个 I/O 密集型进程:

sysbench  --threads=1 --time=0 --max-requests=0  fileio --file-num=1 --file-total-size=10G --file-io-mode=sync --file-extra-flags=direct --file-test-mode=rndrd run

procs -----------memory---------- ---swap-- -----io---- -system-- ------cpu-----
 r  b   swpd   free   buff  cache   si   so    bi    bo   in   cs us sy id wa st
 3  1      0 7130308  27704 763592    0    0 62000    12 4503 8577  3  5 69 20  3
 2  1      0 7127144  27728 763592    0    0 67098    14 4810 9253  2  5 70 20  2
 2  1      0 7128448  27752 763592    0    0 72760    15 5179 9946  2  5 72 20  1
 4  0      0 7133068  27776 763588    0    0 69566    29 4953 9562  2  5 72 21  1
 2  1      0 7131328  27800 763576    0    0 67501    15 4793 9276  2  5 72 20  1
 2  0      0 7128136  27824 763592    0    0 59461    15 4316 8272  2  5 71 20  3
 3  1      0 7129712  27848 763592    0    0 64139    13 4628 8854  2  5 70 20  3
 2  0      0 7128984  27872 763592    0    0 71027    18 5068 9718  2  6 71 20  1
 1  0      0 7128232  27884 763592    0    0 69779    12 4967 9549  2  5 71 20  1
 5  0      0 7128504  27908 763592    0    0 66419    18 4767 9139  2  5 71 20  1

尽管这个进程完全是 I/O 密集型的,但我们可以看到 IOWait (wa) 不是特别高,不到 25%。在具有 32、64 或更多内核的大型系统上,这种完全出现 IO 瓶颈的进程几乎是不可见的,会产生个位数的 IOWait 百分比。

因此,高 IOWait 表明系统中有许多进程在等待磁盘 I/O,但即使 IOWait 低,磁盘 I/O 也可能成为系统上某些进程的瓶颈。

如果 IOWait 不可靠,你可以使用什么来提供更好的可见性?

首先,看一下特定应用的可观察性。应用程序,如果它被很好地检测,往往最清楚什么时候它被磁盘约束,以及什么特定的任务被 I/O约束。

如果你只能访问 Linux 指标,请查看 vmstat 中的 "b"列,它对应于磁盘 I/O 上阻塞的进程。这将显示此类进程,即使是并发的 CPU 密集型负载,也会屏蔽 IOWait:

最后,你可以查看每个进程的统计信息以了解哪些进程正在等待磁盘 I/O。

以上译自 https://www.percona.com/blog/understanding-linux-iowait/

2什么是 iowait 以及它如何影响 Linux 性能

I/O 等待或者 iowait、wait、wa、%iowait 或 wait% 通常由 top、sar、atop 等 Linux 命令行系统监控工具显示。就其本身而言,它是让我们深入窥探 Linux 系统性能的众多性能统计数据之一。

最近与一位新客户的交谈中提到了 I/O 等待。在我们的支持电话中,他们报告说他们的 32 CPU 核心系统上的负载峰值为 60 到 80。这导致了页面加载缓慢、超时和间歇性中断。原因呢?存储 I/O 瓶颈最初是由持续高的 iowait 所表示,后来通过额外调查得到证实。

什么是 I/O 等待?I/O 等待是如何影响 Linux 服务器性能的?我们如何监控和减少与 I/O 等待相关的问题?继续阅读以寻找这些问题的答案。

3什么是 I/O 等待?

I/O 等待适用于 Unix 和所有基于 Unix 的系统,包括 macOS、FreeBSD、Solaris 和 Linux。

I/O 等待 (iowait) 是 CPU(或多个 CPU)空闲的时间百分比,在此期间系统有待处理的磁盘 I/O 请求。(来源:man sar)top man 手册页给出了这个简单的解释:"I/O 等待 = 等待 I/O 完成的时间。" 换句话说,I/O 等待的存在告诉我们系统空闲时它可以处理未完成的请求。

"iowait shows the percentage of time that the CPU or CPUs were idle during which the system had an outstanding disk I/O request." –  iostat man page.

在使用 Linux top 和其他工具时,你会注意到 CPU(及其核心)在以下状态下运行:us(用户态)、sy(内核态)、id(空闲)、ni(nice)、si(软中断)、hi(硬中断)、st(steal)和 wa(等待)。其中,用户态、内核态、空闲状态和等待状态的值加起来应为 100%。请注意,"idle"  和 "wait" 是不同的。"idle" CPU 表示没有工作负载存在,而另一方面,"wait" (iowait) 表示 CPU 何时处于空闲状态等待未完成的请求。

如果 CPU 空闲,内核将确定任何来自 CPU 的未完成 I/O 请求(比如 SSD 或 NFS)。如果有,则 "iowait" 计数器递增。如果没有任何待处理的请求,则 "idle" 计数器会增加。

4I/O 等待和 Linux 服务器性能

值得注意的是, iowait 有时可以指示吞吐量瓶颈,而在其他时候,iowait 可能完全没有意义。有可能拥有高 iowait 的健康系统,但也可能有完全没有 iowait 的存在瓶颈的系统。

I/O 等待只是 CPU / CPU 核心的指示状态之一。高 iowait 意味着你的 CPU 正在等待请求,但你需要进一步调查以确认来源和影响。

例如,服务器存储(SSD、NVMe、NFS 等)几乎总是比 CPU 性能慢。因此,I/O 等待可能会产生误导,尤其是涉及到随机读/写工作负载时。这是因为 iowait 仅测量 CPU 性能,而不测量存储 I/O。

虽然 iowait 表明 CPU 可以处理更多的工作负载,但根据服务器的工作负载以及负载如何执行计算或使用存储 I/O,并不总是可以解决 I/O 等待。或者实现接近于零的值是不可行的。

根据最终用户体验、数据库查询健康状况、事务吞吐量和整体应用程序健康状况,你必须决定报告的 iowait 是否表明 Linux 系统性能不佳。

例如,如果你看到 1% 到 4% 的低 iowait,然后将 CPU 升到 2 倍的性能,iowait 也会增加。具有相同存储性能的 2 倍更快的 CPU = ~ 2 倍的等待时间。你需要考虑你的工作负载来确定应该首先关注哪些硬件。

5监控和减少 I/O 等待相关问题

让我们看看一些用于监视 Linux 上的 I/O 等待的有价值的工具。

  • atop – 使用 -d 选项运行它或按 d 切换磁盘统计视图。
  • iostat – 尝试使用 -xm 2 选项进行扩展统计,以兆字节为单位,以两秒为间隔。
  • iotop – 类似 top 的 I/O 监视器。尝试使用 -oPa 选项来仅显示活动进程的累积 I/O。
  • ps – 使用 auxf,那么在"STAT"列下,"D"通常表示磁盘 iowait。
  • strace - 查看进程执行的实际操作。参阅 strace man 手册。
  • lsof – 确定你负责的进程后,使用 -p [PID] 查找特定文件。

减少 I/O 等待相关问题

采取以下步骤减少与 I/O 等待相关的问题。

  • 优化应用程序的代码和数据库查询。这可以大大降低磁盘读/写的频率。这应该是你的第一个方法,因为应用程序越高效,在硬件上的长期花费就越少。另请参阅:100 应用程序性能监控 (APM) 和可观察性解决方案
  • 使 Linux 系统和软件版本保持最新。这不仅对安全性更好,而且通常情况下,最新支持的版本会提供显着的性能改进,无论是 Nginx、Node.js、PHP、Python 还是 MySQL。
  • 确保有空闲的可用内存。足够的空闲内存,以便大约一半的服务器内存用于内存缓冲区和缓存,而不是交换和换页到磁盘。当然,这个比例会因情况而异。因此,请确保你没有交换,并且内核缓存压力不会因缺少可用内存而变高。
  • 调整系统、存储设备和 Linux 内核以提高存储性能和使用寿命。
  • 最后,如果一切都失败了:将存储设备升级到更快的 SSD、NVMe 或其他高吞吐量存储设备。

6结论

iowait 统计数据是一个有用的性能统计数据,可用于监控 CPU 利用率健康状况。当 CPU 空闲并且可以执行更多计算时,它会通知系统管理员。然后,我们可以使用可观察性、基准测试和跟踪工具(例如上面列出的那些工具)来综合了解系统的整体 I/O 性能。你的主要目标应该是消除因等待磁盘、NFS 或其他与存储相关的 I/O 而直接导致的任何 iowait。

以上译自 https://haydenjames.io/what-is-iowait-and-linux-performance/

7小结

这篇文章是今天上午老板在群里分享的,我看到后十分有感触,因为我之前阅读过类似的文章,知晓 iowait 这个参数的坑,Linux 中的解释是

Show the percentage of time that the CPU or CPUs were idle during which the system had an outstanding disk I/O request.

也就是说 CPU 在等待磁盘 I/O 请求时,处于空闲状态的时间百分比(此时正在运行着 idle 进程,空闲的时候也会运行一个进程)。

可以看出,如果系统处于 iowait 状态,那么必须满足以下两个条件:

  1. 系统中存在等待 I/O 请求完成的进程。
  2. 系统当前正处于空闲状态,也就是说没有可运行的进程。

主要代码流程如下

void account_process_tick(struct task_struct *p, int user_tick)
{
    cputime_t one_jiffy_scaled = cputime_to_scaled(cputime_one_jiffy);
    struct rq *rq = this_rq();

    // 1. 如果当前进程处于用户态,那么增加用户态的CPU时间
    if (user_tick) {
        account_user_time(p, cputime_one_jiffy, one_jiffy_scaled);
    }
    // 2. 如果前进程处于内核态,并且不是idle进程,那么增加内核态CPU时间
    else if ((p != rq->idle) || (irq_count() != HARDIRQ_OFFSET)) {
        account_system_time(p, HARDIRQ_OFFSET, cputime_one_jiffy,
                            one_jiffy_scaled);
    }
    // 3. 如果当前进程是idle进程,那么调用account_idle_time()函数进行处理
    else {
        account_idle_time(cputime_one_jiffy);
    }
}

void account_idle_time(cputime_t cputime)
{
    struct cpu_usage_stat *cpustat = &kstat_this_cpu.cpustat;
    cputime64_t cputime64 = cputime_to_cputime64(cputime);
    struct rq *rq = this_rq();

    // 1. 如果当前有进程在等待IO请求的话,那么增加iowait的时间
    if (atomic_read(&rq->nr_iowait) > 0) {
        cpustat->iowait = cputime64_add(cpustat->iowait, cputime64);
    }
    // 2. 否则增加idle的时间
    else {
        cpustat->idle = cputime64_add(cpustat->idle, cputime64);
    }
}

也就是说:

  1. 如果当前有进程在等待 I/O 请求的话,那么增加 iowait 的时间。
  2. 如果当前没有进程在等待 I/O 请求的话,那么增加 idle 的时间。

所以正确解释是:有进程在等待 IO,被阻塞了,并且当前系统是空闲的,没有其他进程在运行。

怎么样?各位是不是涨知识了?又比如经常被用来判断磁盘饱和度的 %util 指标,各位可能会在不少文章中看到类似结论:

如果 %util 接近 100%,说明产生的I/O请求太多,I/O系统已经满负荷,该磁盘可能存在瓶颈。

这个结论也是不严谨的,%util 表示该设备有I/O(即非空闲)的时间比率,不考虑 I/O 有多少,只考虑有没有。由于现代硬盘设备都有并行处理多个 I/O 请求的能力,所以 %util 即使达到 100% 也不意味着设备饱和了。举个简化的例子:某硬盘处理单个 I/O 需要0.1秒,有能力同时处理 10 个I/O 请求,那么当 10 个 I/O 请求依次顺序提交的时候,需要 1 秒才能全部完成,在 1 秒的采样周期里 %util 达到 100%;而如果 10 个 I/O 请求一次性提交的话,0.1 秒就全部完成,在 1 秒的采样周期里 %util 只有 10% 。可见,即使 %util 高达 100%,硬盘也仍然有可能还有余力处理更多的 I/O 请求,即没有达到饱和状态。很可惜,iostat 并没有用来判断饱和度的指标。

所以,阅读此文后,千万不要再凭借看到一个 iowait 高指标就判断 IO 瓶颈了。




推荐本站淘宝优惠价购买喜欢的宝贝:

image.png

本文链接:https://hqyman.cn/post/8882.html 非本站原创文章欢迎转载,原创文章需保留本站地址!

分享到:
打赏





休息一下~~


« 上一篇 下一篇 »

发表评论:

◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。

请先 登录 再评论,若不是会员请先 注册

您的IP地址是: