什么等等? I/O Wait ≠ I/O 瓶颈?

本文地址:什么等等? I/O Wait ≠ I/O 瓶颈? | 深入浅出 eBPF

  • 1. I/O Wait 定义
  • 2. 测试验证
  • 3. 进一步明确磁盘吞吐和读写频繁进程
  • 4. 内核 CPU 统计实现分析
  • 5. 总结
  • 参考资料

1. I/O Wait 定义

I/O Wait 是针对单个 CPU 的性能指标,表示当 CPU 分发队列(在睡眠态)里有线程被阻塞在磁盘 I/O 上时消耗的空闲时间。CPU 的空闲时间划分成无所事事的真正空闲时间和阻塞在磁盘 I/O 上的时间。较高的 CPU I/O Wait 时间表示磁盘可能存在瓶颈,导致 CPU 等待而空闲。如果你看到这个定义,有点雾中看花的感觉,那么请移步往后,相信你看完本文的测试验证过程,再回来读上述定义的时候一定会有不同的认识。

2. 测试验证

本地测试验证环境为:Ubuntu 22.04, CPU 12 核,内核 6.2.0-34-generic

$ cat /proc/cpuinfo |grep processor|wc -l
12

我们通过 sysbench 工具进行对应压测验证,同时观察对应的 I/O Wait 的表现。注意为了更好体现效果,我们测试 I/O 的过程中,将 threads 设置为 CPU 的全部核数的 50%(本文为 --threads=6

$ sudo apt-get update 
$ sudo apt install sysbench# 提前准备测试的数据
$ sysbench  --threads=6 --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 prepare# 运行压测
$ sysbench  --threads=6 --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
...
Periodic FSYNC enabled, calling fsync() each 100 requests.
Calling fsync() at the end of test, Enabled.
Using synchronous I/O mode
Doing random read test
Initializing worker threads...Threads started!

在运行 I/O 压测过程中,我们使用 top 命令查看 CPU 占用情况,可以看到 wa (I/O wait)值展示,图中为 38.3 %:

b53e1bc14c2e2acc911b355c1cff92dc

看到这里,给我们的感觉是 CPU I/O Wait 使用应该正确展示出了 I/O wait 的 CPU 使用情况。在我们一直保持 sysbench I/O 测试的同时,同时启动一个 CPU 密集类型的测试,然后我们观测 top 中的 wa 的值。这里测试我们设置使用所有的 CPU 核数。

1
$ sysbench --threads=`grep processor /proc/cpuinfo|wc -l` --time=0 cpu run

208a97d04ca69e6f6426d6641386cd2f

发生了什么,有没有觉得神奇,wa 变为了 0.0?给我们的感觉是 I/O 的瓶颈完全消失了?难道运行系统中的 I/O 压力突然消失了?我们可以注意到在运行的进程中两个 sysbench 进程在运行,分别对应于 I/O 和 CPU 测试的进程,所以实际运行情况看,I/O 的瓶颈仍然存在。

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

结合我们上述的测试, I/O Wait 好像并不可靠,那么我们使用什么来提供更好 I/O 的可见性? 我们可以使用 vmstat 工具来进行查看。

在运行 I/O 和 CPU 负载的同时,我们使用 vmstat 工具观测,同时在一定时间测试后我们停掉 CPU 负载测试的 sysbench 进程,下图我们可以明显看到停止前后的效果对比趋势。

1b6bdde712f44cbbad2e97cc49c1eb8a

首先,我们可以发现 wa 列在运行 CPU 负载测试前后的变化比较明显,首列中的 r 的数据也得到了对应的体现(r 表示运行的任务数,运行 CPU 负载测试时的值为 12)。

15b628ce5fef0c35cc91208a3af1cef9

vmstat 展示数据中的 “b” 列代表的是对应于磁盘 I/O 上阻塞的进程,我们可以看到在运行 CPU 负载 sysbench 前后该值基本保持在 6 左右, 6 正是我们在运行 I/O 测试时候指定的 sysbench 中对应的 --threads=6 。该列值表明,即使在 wa 为 0.0 时,系统运行中仍然存在 6 个进程在等待 I/O。

fa1f24a7768d04a8dcb0dac2a419e01c

3. 进一步明确磁盘吞吐和读写频繁进程

在通过 vmstat b 列确定存在进程 I/O 等待情况后,我们也可以使用 iostat 和 iotop 进行进一步定义。

iostat 1 nvme0n1

nvme0n1 为本地磁盘

a921d64010d80eb7977092be6a3a3e8c

其中

  • tps:每秒事务数(IOPS)
  • kB_read/s、kB_wrtn/s : 每秒读取的 KB 数和每秒写入的 KB 数量

iotop 工具可快速定位到当前系统中读写频繁的进程信息。

3cacbc9f87bdce0a9fe755f60a3efbf2

4. 内核 CPU 统计实现分析

在通过上述分析以后,我们尝试从内核代码实现维度进行简单分析(内核代码代码版本 6.2.0 ):

cputime.c#L483

void account_process_tick(struct task_struct *p, int user_tick)
{u64 cputime, steal;if (vtime_accounting_enabled_this_cpu())return;if (sched_clock_irqtime) {irqtime_account_process_tick(p, user_tick, 1);return;}cputime = TICK_NSEC;steal = steal_account_process_time(ULONG_MAX);if (steal >= cputime)return;cputime -= steal;// 1. 如果当前进程处于用户态,那么增加用户态的 CPU 时间if (user_tick) account_user_time(p, cputime);// 2. 如果前进程处于内核态,并且不是 idle 进程,那么增加内核态 CPU 时间else if ((p != this_rq()->idle) || (irq_count() != HARDIRQ_OFFSET))account_system_time(p, HARDIRQ_OFFSET, cputime);// 3. 如果当前进程是 idle 进程,那么调用 account_idle_time() 函数进行处理elseaccount_idle_time(cputime);
}

account_idle_time 函数是统计当前 CPU 空闲的实现,可以看到如果 CPU 上有 nr_iowait 的值不为 0, 空余时间则会统计到 iowait 中,否则则会统计到 idle 列中。

cputime.c#L218

void account_idle_time(u64 cputime)
{u64 *cpustat = kcpustat_this_cpu->cpustat;struct rq *rq = this_rq();// 1. 如果当前有进程在等待 I/O 请求的话,那么增加 iowait的时间if (atomic_read(&rq->nr_iowait) > 0)cpustat[CPUTIME_IOWAIT] += cputime;// 2. 否则增加idle的时间elsecpustat[CPUTIME_IDLE] += cputime;
}

通过代码我们可以明确看到,如果系统处于 I/O wait 状态,那么必须满足以下两个条件:

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

5. 总结

经过上述测试,我们可以看到 I/O Wait 可能是一个令人非常困惑的指标。如果 CPU 密集型的进程运行,I/O Wait 的值可能会降低,但是尽管 I/O Wait 指标下降了,但磁盘 I/O 仍然和原来一样阻塞进程执行。所以在判断是否存在 I/O 瓶颈时,我们不能简单依靠 I/O Wait 值的高低来断定系统是否存在 I/O 瓶颈。

相信读完这篇文档的童鞋们,后续再也不会跳进 I/O Wait 指标的坑里了,那么这也就是本文的价值所在了。

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

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

相关文章

Vue3数据交互axios

我是南城余!阿里云开发者平台专家博士证书获得者! 欢迎关注我的博客!一同成长! 一名从事运维开发的worker,记录分享学习。 专注于AI,运维开发,windows Linux 系统领域的分享! 本…

铁山靠之——HarmonyOS基础 - 1.0

HarmonyOS学习第一章 一、HarmonyOS简介1.1 安装和使用DevEco Studio1.2 环境配置1.3 项目创建1.4 运行程序1.5 基本工程目录1.5.1 工程级目录1.5.2 模块级目录1.5.3 app.json51.5.4 module.json51.5.5 main_pages.json 二、TypeScript快速入门2.1 简介2.2 基础类型2.2.1 布尔值…

linux内存寻址原来那么简单

内存寻址 内存寻址听起来高大上,其实真实处理起来很简单,以常见的80x86架构为例,有三种不同的地址: 逻辑地址线性地址物理地址 内存控制单元(MMU)通过分段单元的硬件电路把一个逻辑地址转化为线性地址,通过分页单元的…

华硕主板开机只进入Bios模式不进入Windows系统

华硕电脑进入bios界面解决办法 1.可以按平常方法多重启几下(bios界面按f10确认保存) 2.是固态硬盘的地方看看是否有松动 插回去就可以了3.图形界面bios先按f7进入高级模式,【security】菜单,通过方向键选择【secure Boot】选项&am…

【MATLAB库函数系列】线性调频Z(Chirp-Z,CZT)的MATLAB源码和C语言实现

在上一篇博客 【数字信号处理】线性调频Z(Chirp-Z,CZT)算法详解 已经详细介绍了CZT变换的应用背景和原理,先回顾一下: 回顾CZT算法 采用 FFT 算法可以很快计算出全部 N N N点 DFT 值,即Z变换 X ( z ) X(z) <

Python 数据分析 Matplotlib篇 增加注释【plt.text() plt.annotate()】(第3讲)

Python 数据分析 Matplotlib篇 增加注释【plt.text() & plt.annotate()】(第3讲)         🍹博主 侯小啾 感谢您的支持与信赖。☀️ 🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔…

C# SqlSugar 数据库 T4模板

生成效果 模板代码 <# template debug"false" hostspecific"true" language"C#" #> <# output extension".cs" #> <# assembly name"System.Core" #> <# assembly name"System.Data" #>…

2024 年全球顶级的 4 款 PDF 转换器软件

PDF 是一种广泛使用的共享文档和文件的格式。但是&#xff0c;有时您可能需要将 PDF 文件转换为其他格式&#xff08;例如 Word 或 Excel&#xff09;&#xff0c;以便编辑或操作内容。这就是 PDF 转换器软件派上用场的地方。 有许多 PDF 转换器软件可供选择&#xff0c;有免费…

Java进阶(第六期): Arrays类(数组工具)、冒泡排序、选择排序、二分查找、【正则表达式】、Java正则爬取信息

文章目录 一、Arrays1.1代码示例&#xff1a; 二、冒泡排序2.1 代码示例 三、选择排序3.1 代码示例 四、二分查找4.1 代码示例 &#xff08;这里采用乱序数组&#xff09; 五、正则表达式5.1 正则表达式的基本使用5.2 正则表达式爬取信息练习 Java进阶&#xff08;第六期&#…

CUMT--Java复习--文件及IO流

目录 一、文件 1、文件系统和路径 2、File类 3、FilenameFilter接口 二、IO流 1、流的分类 2、流的体系结构 三、字节流 1、InputStream 2、OutputStream 四、字符流 1、Reader 2、Writer 五、过滤流和转换流 1、过滤流 2、转换流 六、序列化 1、对象序列化…

使用PE信息查看工具和Dependency Walker工具排查因为库版本不对导致程序启动报错的问题

目录 1、问题说明 2、问题分析思路 3、问题分析过程 3.1、使用Dependency Walker打开软件主程序&#xff0c;查看库与库的依赖关系&#xff0c;找出出问题的库 3.2、使用PE工具查看dll库的时间戳 3.3、解决办法 4、最后 VC常用功能开发汇总&#xff08;专栏文章列表&…

SRE 与 DevOps:你知道它们之间区别吗?

公众号「架构成长指南」&#xff0c;专注于生产实践、云原生、分布式系统、大数据技术分享 DevOps专注于消除阻碍开发和运维之间协作的隔阂&#xff0c;而SRE致力于设计和实施可扩展、可靠的系统&#xff0c;确保最大可靠性。 这篇文章将探讨DevOps和SRE之间的差异&#xff0c…