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

本文探讨了I/OWait指标的误解,通过实验展示了即使I/OWait值低,磁盘I/O仍可能成为瓶颈。作者使用sysbench、vmstat和内核代码分析,强调了判断I/O瓶颈需综合考虑多个因素。

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

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() 函数进行处理
	else
		account_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的时间
	else
		cpustat[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 指标的坑里了,那么这也就是本文的价值所在了。

<think>嗯,用户需要记录CentOS服务器测试前后的关键监控参数,包括CPU、内存和I/O使用情况。这属于系统性能监控范畴,需要选择合适的工具和持久化方案。 用户可能正在准备压力测试或性能优化,需要基线数据作为对比依据。考虑到测试场景的特殊性,应该推荐轻量级方案避免干扰测试结果,同时确保数据可追溯性。 从技术实现看,有几个关键点需要考虑: 首先是监控工具的选择。top/htop适合实时查看但难以记录历史数据;vmstat能提供全面的I/O统计;free是内存监控的标准工具;而sar作为sysstat组件可以周期性采集数据,最适合这个场景。 其次是数据记录方式。crontab定时任务是最简单的自动化方案,但要注意避免监控本身消耗过多资源。测试前后需要手动触发开始/结束标记,比如用时间戳文件区分阶段。 最后是数据整理。awk/sed能快速提取关键指标,但用户可能需要更直观的可视化。这里可以分层次建议:基础方案用文本处理,进阶方案用Excel或Grafana。 特别注意引用[3]提到的性能分析逻辑链:当系统缓慢时,需要关联查看I/O等待时间和CPU空闲时间。因此监控方案必须能同时捕获这两类数据,这正是sar的优势所在。 对于用户未明确但可能需要的点: - 监控时长:建议测试前后各延长30分钟 - 安全考虑:/var/log/sa目录权限设置 - 异常处理:邮件报警集成(引用[1]的邮件方案可借鉴)</think>在CentOS服务器上记录和整理测试前后的关键监控参数,可通过以下步骤实现: ### 一、监控工具选择与配置 1. **安装`sysstat`套件**(含`sar`命令) ```bash sudo yum install sysstat sudo systemctl enable --now sysstat # 启用数据收集 ``` *每秒收集一次数据,存储于`/var/log/sa/`* 2. **核心工具功能** - `sar`:综合性能数据(CPU、内存、I/O) - `vmstat`:实时虚拟内存和CPU统计 - `free`:内存使用情况 - `iostat`:磁盘I/O详情 --- ### 二、测试前后数据记录流程 #### (1) 测试前准备 ```bash # 创建记录目录 mkdir -p ~/performance_logs echo "===== TEST START: $(date) =====" > ~/performance_logs/full_report.log ``` #### (2) 启动后台监控 ```bash # 每5秒采集一次,持续到测试结束 nohup sar -u -r -b -n DEV 5 > ~/performance_logs/sar_raw.log & echo $! > ~/performance_logs/monitor.pid # 保存进程ID ``` #### (3) 测试结束后 ```bash # 停止监控进程 kill $(cat ~/performance_logs/monitor.pid) echo "===== TEST END: $(date) =====" >> ~/performance_logs/full_report.log ``` --- ### 三、关键指标提取与整理 #### 1. CPU使用率分析 ```bash # 提取CPU平均使用率 sar -u -f ~/performance_logs/sar_raw.log | awk ' /Average:/ && $NF ~ /[0-9]/ { printf "CPU使用率: %.2f%% (用户:%.2f%%, 系统:%.2f%%)\n", 100-$NF, $3, $5 }' >> ~/performance_logs/full_report.log ``` #### 2. 内存使用率分析 ```bash # 计算内存峰值使用率 sar -r -f ~/performance_logs/sar_raw.log | awk ' /Average:/ { used=($3-$5-$6)/1024; total=$2/1024; printf "内存使用率: %.2f%% (%.1fG/%.1fG)\n", (used/total)*100, used/1024, total/1024 }' >> ~/performance_logs/full_report.log ``` #### 3. I/O性能分析 ```bash # 获取磁盘平均负载 sar -b -f ~/performance_logs/sar_raw.log | awk ' /Average:/ { printf "磁盘I/O: tps=%.1f, 读%.1fMB/s, 写%.1fMB/s\n", $2, $3*512/1048576, $4*512/1048576 }' >> ~/performance_logs/full_report.log ``` --- ### 四、自动化脚本示例 ```bash #!/bin/bash # 启动监控 start_monitor() { sar -u -r -b 5 > ~/performance_logs/sar_$1.log & echo $! > /tmp/monitor.pid } # 停止并生成报告 stop_monitor() { kill $(cat /tmp/monitor.pid) generate_report $1 } # 报告生成函数 generate_report() { # 此处集成上述分析命令 ... } ``` **用法:** ```bash ./monitor.sh start # 测试前执行 # 运行测试任务... ./monitor.sh stop # 测试后执行 ``` --- ### 五、数据解读要点 1. **CPU瓶颈判断** - 当`%idle`持续低于20%时需警惕(引用[3]) - `%iowait`突增预示磁盘I/O问题(如数据库查询过载时常见,引用[4]) 2. **内存泄露迹象** - `kbmemfree`持续下降且`kbcached`无增长 - Java应用GC频繁导致CPU飙升(引用[4]案例) 3. **I/O性能阈值** - `tps > 500`或`await > 20ms`需优化磁盘配置 > **最终报告路径:** `~/performance_logs/full_report.log` > 示例输出: > ``` > ===== TEST START: Fri Jul 26 10:00:00 CST 2024 ===== > CPU使用率: 78.42% (用户:68.15%, 系统:10.27%) > 内存使用率: 83.17% (14.2G/17.1G) > 磁盘I/O: tps=642.3, 读45.1MB/s, 写120.7MB/s > ===== TEST END: Fri Jul 26 11:30:15 CST 2024 ===== > ``` ---
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值