Skip to content

Commit

Permalink
feat: linux disk io
Browse files Browse the repository at this point in the history
  • Loading branch information
ryan4yin committed Nov 15, 2023
1 parent 8ccb698 commit 307c935
Show file tree
Hide file tree
Showing 2 changed files with 80 additions and 0 deletions.
80 changes: 80 additions & 0 deletions linux/Linux IO 性能问题与解决思路.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
# Linux SSD IO 性能问题与解决思路


## 一、磁盘 IOPS 跟读写速率都很低,但 IO 利用率一直 100%,应用程序响应很慢

### 1 案例一:AIGC 程序

环境:

1. 系统:Amazon Linux 2
2. 磁盘:AWS GP3 类型,IOPS 3000,吞吐量 750MB/s
3. 应用程序:AIGC 推理服务

现象:

node-exporter 提供的磁盘相关监控指标:

![](./_img/node-exporter-high-io-wait.webp)

AIGC 推理程序在首次运行时会因为 IO 问题卡 15 分钟,后续运行时因为数据已经缓存到内存中,所以不会再出现这种卡顿。

把 GP3 的吞吐上限改到 750MB/s,没任何改善。
鉴于监控中的 IOPS 也不超过 100,预计把 IOPS 调高也没啥用。


### 2 案例二:Kafka 节点

线上环境中经常遇到某 Kafka 节点因为磁盘 IO 跑满导致响应满,无法正常提供服务。
但监控看 IOPS 跟读写速率都很低,只有 IO 使用率一直 100%。


### 3 排查思路

#### 3.1. 底层原理分析

要搞明白这个问题的原因,需要首先理解 HDD/SSD 的性能区别,以及 Linux 系统中相应的驱动程序架构,如下这篇文章对此有比较详细的说明:

- [【阿里云总监课】存储系统设计——NVMe SSD性能影响因素一探究竟](https://developer.aliyun.com/article/658502)

简单的说,HDD 是通过单个磁头读写数据,所以针对 HDD 的 AHCI 规范只定义了一个命令队列,即不论 CPU 有几个核,HDD 都只能同时处理一个 IO 请求。

而 SSD 的性能全方位地超越了 HDD,并且硬件层面就支持多个并发 IO,所以针对 SSD 的 NVMe 规范采用了多队列设计。从软件层面看,每个 CPU Core 都可以创建一对 Queue Pair 和 SSD 进行数据交互。

SSD 的性能受两方面的影响:

1. 硬件层面:比如 NAND Flash 的类别(TLC/QLC/SLC/MLC/...)、后端通道数(CE数量)及总线频率、SSD 控制器的处理能力与架构、PCIe 带宽、使用寿命等等。
1. 由于我们这里主要考虑云服务场景,硬件层面的因素不展开讨论。
2. 软件层面:即 Linux 系统层面
1. **数据布局方式**:数据布局方法需要充分考虑NAND Flash中的并发单元,如何将IO操作转换成NAND Flash的并发操作,这是数据布局需要考虑的问题。例如,采用数据交错的方式在多通道page上进行数据布局,通过这种方式可以优化顺序带宽。
2. **垃圾回收 / wear leveling 调度方法**:数据回收、wear leveling、data retention等操作会产生大量的NAND Flash后端流量,后端流量直接反应了SSD的写放大系数,也直接体现在后端带宽的占用。
3. **Overprovisioning 预留空间**:为了解决坏块、垃圾回收等问题,在SSD内部预留了一部分空闲资源作为备用,即 Overprovisioning 空间。
4. **IO调度算法**:NAND Flash具有严重的性能不对称性,Flash Erase和Program具有ms级延迟,Flash read的延迟在us级。因此,如何调度Erase、Program以及read是SSD后端设计需要考虑的问题。另外,前端IO以及背景IO之间的调度也是需要权衡考虑,通过IO调度可以达到最佳性能表现。在IO调度过程中,还需要利用NAND Flash的特性,例如Program Suspension,通过这些特性的利用,最优化SSD前端IO性能。
5. **IO Pattern**:IO Pattern影响了SSD内部的GC数据布局,间接影响了GC过程中的数据搬移量,决定了后端流量。当IO Pattern为全顺序时,这种Pattern对SSD内部GC是最为友好的,写放大接近于1,因此具有最好的性能;当IO Pattern为小块随机时,会产生较多的GC搬移数据量,因此性能大为下降。在实际应用中,需要通过本地文件系统最优化IO Pattern,获取最佳性能。
6. FTL算法 / Bit error 处理机制,这几个不展开了。
7. 系统层面的系统优化:比如内存中的 Page Cache、文件系统、SSD 驱动程序的实现方式等等。

我们在前面看到的两个案例中,都是因为 IO 利用率一直 100%,但 IOPS 和读写速率都很低。GP3 是 AWS 目前的主流 EBS 磁盘类型,在软件层面肯定能做一些优化。


#### 3.2. 排查

首先我们已经通过 node-exporter 对应的 grafana 监控面板,确定了当前磁盘 IO 利用率一直 100%、IOPS 与读写速率都很低,一开始读的 wait 显然非常高,能确认是卡在了读上面。

进一步可用 `iotop` 定位到消耗 IO 的进程,然后用 `strace -f -p $pid -T -tt -e read``lsof -p $pid` 定位到导致 IO 高的文件。

#### 4. 解决思路

常见手段:

1. 针对磁盘和应用程序 I/O 模式的特征,我们可以选择最适合的 I/O 调度算法。云主机一般都默认用 `noop` 算法,但对于 kafka / mysql / aigc 等应用场景,`deadline` 可能更合适。
1. If in doubt, use the `deadline` scheduler.
2. 对于顺序读较多的场景,调整 /sys/block/sdb/queue/read_ahead_kb 的值,增大磁盘的预读数据。
3. 对应用程序进行磁盘级别的隔离,比如把 kafka 的数据目录和日志目录这些 IO 压力较高的目录分别放到不同的磁盘上。
4. 应用程序层面的优化,比如 kafka 自身就通过追加写的方式来减少磁盘随机写的次数,从而提高性能。kafka 本身也有一些 IO 行为相关的参数可调整。
5. 对于云主机,可以考虑使用本地存储卷(Local SSD / Local NVMe Storage),它的性能远高于 AWS EBS / Aliyun ESSD 等云磁盘,但其中的数据在多种情况下并不持久化,需要自己做好数据备份与容灾考量。

## 参考

- [Linux性能优化实践-磁盘I/O篇](https://mp.weixin.qq.com/s/mLEVKXShnifHbQiQrgJGSA)

Binary file added linux/_img/node-exporter-high-io-wait.webp
Binary file not shown.

0 comments on commit 307c935

Please sign in to comment.