本文首先介绍些磁盘I/O相关的知识,然后会提供一个排查磁盘I/O问题的套路,最后再以一个线上遇到的磁盘I/O导致的问题案例进行分析和排查套路展示。
磁盘 I/O介绍
首先,什么是磁盘I/O呢,他是指计算机与磁盘(如HDD机械硬盘、SSD固态硬盘)之间的数据读写操作。磁盘I/O和cpu,内存,网络I/O等,都是linux服务器的主要资源,如果磁盘I/O遇到了瓶颈,会严重影响到机器上部署的服务,导致服务响应缓慢甚至几乎不能正常处理请求,因此磁盘I/O对于线上服务的稳定性来说是一个重大的影响因素,也是排查问题时不能跳过的一个排查方向。
如果磁盘I/O到达了瓶颈,可能会出现以下情况:
系统响应延迟
- 应用服务器等待磁盘 I/O 完成,导致请求堆积。
- 高并发场景下可能出现超时(如 API 响应变慢)。
CPU利用率下降(I/O Wait 高)
- 在
top或vmstat中,%wa(I/O Wait)指标飙升。 - CPU 因等待 I/O 而闲置,资源浪费。
磁盘性能指标
那么,如何判断现在是否已经遇到了磁盘 I/O瓶颈呢? 我们可以通过几个主要的磁盘性能指标来进行判断,他们分别是 使用率,饱和度,IOPS,吞吐量和响应时间。
- 使用率:他是磁盘处理I/O的时间百分比,他代表着一段时间内,有多少时间磁盘是有在处理I/O的。
- 饱和度:是指I/O在队列里等待的程度,可以通过磁盘等待队列的长度粗略估计,如果等待队列中一直有I/O等待处理,说明磁盘饱和度高,无法及时处理所有的I/O
- IOPS:是磁盘每秒处理的I/O请求数
- 吞吐量:是单位时间内磁盘成功传输的数据量,通常以 MB/s衡量。
- 响应时间:是磁盘完成单次 I/O 操作所需的时间,单位通常是 毫秒(ms) 。
需要注意的是,磁盘使用率这个指标只表明磁盘有在处理I/O的时间百分比,如果他到100%了,也并不能说磁盘就不能处理更多的I/O请求了。比如,现在使用率是70%,他代表1秒内有70%的时间磁盘都是有在处理I/O的,在处理I/O的时间内,可能处理的是1个读请求,也可能处理的是100个读请求,即使使用率到100%了,也不代表就不能处理更多的I/O请求了。
有了判断磁盘I/O瓶颈的指标,现在我们还需要能获取对应指标的工具,以及指标的上限值,这样我们就可以通过工具获取当前的指标值,然后和上限值进行比对,来判断是否到达上限了。
常见工具
获取指标的常见工具有iostat,vmstat,pidstat,iotop等
- iostat和vmstat都可用于获取系统磁盘的I/O指标,他们的指标是磁盘设备级别的
- pidstat和iotop可以用于获取进程的磁盘使用率,他们是获取进程级指标的工具
| 工具 | 核心功能 | 关键指标 | 执行命令 |
|---|---|---|---|
| iostat | 磁盘 I/O 性能分析 | r/s(读IOPS)、w/s(写IOPS)、rkB/s(读吞吐量)、wkB/s(写吞吐量)、avgqu-sz(平均请求队列长度)、await(响应时间)、%util(利用率) | iostat -x 1 |
| vmstat | 系统整体资源监控 | r(就绪队列)、b(阻塞进程)、bi(读IOPS)、bo(写IOPS)、wa(I/O 等待 CPU 百分比) | vmstat 1 |
| pidstat | 进程级资源占用统计 | kB_rd/s(读吞吐量)、kB_wd/s(写吞吐量) | pidstat -d 1 |
| iotop | 实时进程磁盘 I/O 排名 | DISK READ(读吞吐量)、DISK WRITE(写吞吐量)、IO>(进程I/O 占用 CPU 时间的百分比)、SWAPIN(进程因等待 Swap而阻塞的时间占比) | iotop |
可以通过iostat查看系统的关键指标:
%util(利用率)就是使用率avgqu-sz(平均请求队列长度)可用于估计磁盘的饱和度r/s(读IOPS) +w/s(写IOPS) 就是磁盘的当前IOPS值rkB/s(读吞吐量) +wkB/s(写吞吐量) 就是磁盘的吞吐量await(响应时间) 是磁盘的响应时间
磁盘指标上限值
针对云厂商的磁盘,可以在云厂商的控制台查看对应磁盘性能。比如aws可以在ec2 - ebs界面查看磁盘的性能指标数据,比如下图,IOPS上限是3000,吞吐量上限是125M/s,其中aws还提供了 卷IOPS已超过检查 和 卷吞吐量已超过检查 这两个监控项来查看是否到达磁盘上限,如果大于1则代表超限,到达了I/O瓶颈了。
阿里云也可以通过文档找到对应云盘类型,查看指标上限
磁盘 I/O瓶颈排查流程
下面说下常见的磁盘 I/O瓶颈排查流程:
- 第一步需要做的是先判断是否有磁盘I/O瓶颈,这个可以先通过top 查看cpu使用率,如果其中的cpu的 wa指标比较高,说明有I/O瓶颈。
- 使用iostat -x 1来查看,如果util比较高,比如超过60%,说明可能当前的磁盘的利用率较高,可能有磁盘I/O瓶颈
- 查看iostat的
r/s(读IOPS) +w/s(写IOPS)这两个指标的汇总值,和云厂商的磁盘的iops上限进行对比,如果有时达到或者很接近上限值,则代表IOPS有瓶颈。 有些厂商如aws也提供了监控,可以直接看出此项指标是否有瓶颈。 - 查看iostat的
rkB/s(读吞吐量) +wkB/s(写吞吐量) 这两个指标的汇总值,和云厂商的磁盘的吞吐量上限进行比较,查看是否到达了吞吐量瓶颈。aws的话提供了监控指标,可以直接看出此项指标是否有瓶颈。 - 也可以通过
avgqu-sz(平均请求队列长度)和await(响应时间)指标协助参考,如果这两个值比较高,可能也说明了磁盘性能有问题。 - 确认磁盘有瓶颈之后,可以通过pidstat -d 1和 iotop查看进程级别的磁盘数据,看哪个进程的读写I/O比较高,判断是哪个程序导致的问题
- 定位到程序后,如果想查看是哪段代码导致的问题,可以尝试使用strace命令,通过 strace -p pid 来查看进程执行的系统调用,比如是否经常写入哪个文件等。 可以使用 strace -p -f $pid来跟踪进程的所有线程的系统调用。
- 上一步查看到的系统调用显示的文件可能只有文件描述符,不能看到具体的文件名,可以通过lsof -p pid 来查看进程打开的文件,通过FD字段匹配对应的文件描述符,NAME字段就能看到文件路径和名称。
这里说明下top 中cpu的wa指标,他表示当cpu队列里面有现成被阻塞在磁盘I/O上时消耗的空闲时间。他把cpu的空闲时间分成了无所事事的真正空闲时间,以及阻塞在磁盘I/O上的事件,如果wa较高表示磁盘可能是瓶颈所在,导致cpu等待而空闲。
线上案例分析
某天晚上,突然收到报警,一个kafka的topic堆积数突然增高,说明消费者没有及时处理数据,性能不足无法跟上生产者产生消息的速度。
因为消费者是k8s调度,然后容器化部署在一台机器上的,先通过监控查看了容器的cpu性能数据,发现CPU Throttling高,代表cpu使用率超过了设置的limit,但是奇怪的是,同一台机器上还有其他一个相同的消费者实例,而且两者收到的消息数量基本一致,但是另外一个实例却没有cpu不足的问题,因此排查问题实例的cpu高的原因。
查看实例所在的机器节点的监控信息,发现机器的cpu的磁盘IO使用率不高,但是磁盘的写吞吐量,每秒内I/O操作好事占比,IOPS的读写总值都比较高,其中IOPS更是基本接近了磁盘的IOPS上限,而且是某个时间点之后突增的,因此可以确认机器上的磁盘I/O有瓶颈,并且IOPS已经到达了上限。
这里介绍下,监控里面的node节点是grafana的Node模板,可以参考以下这个地址。 他的CPU使用率中的磁盘IO使用率,就是top中的wa 指标, 每秒磁盘读写容量就是 iostat中的吞吐量指标,每1秒内I/O操作耗时占比就是iostat的util指标。 grafana.com/grafana/das…
分析出机器上有磁盘I/O瓶颈后,进入机器通过pidstat -d 1 查看进程的读写情况。发现有问题的java实例的写入非常高,看来机器节点的写吞吐量增高就是这个服务导致的。因此,结合监控数据可以大致知道,是因为这个服务的写入速度突然异常增高导致的后续一切异常。 后续通过strace和lsof找到对应的文件后,发现是因为一个代码逻辑导致异常打印了很多日志,因此引起了这个问题,处理后问题修复。