背景环境信息:我正在开发一个从 NVMe SSD 流式传输多个音轨的应用程序,并且正在测量系统的性能以确定我需要提供多少缓冲,以避免由于不同的磁盘读取而导致任何音频欠载。
为简单起见,我运行的是一台闲置、无 GUI、真实硬件的 20 核 Linux 服务器,文件系统为 ext4,我将程序设置为仅通过单个线程读取音频数据(在实际使用中,它将使用多个 I/O 线程,但我看到的 SSD 行为类似)。我将其设置为同时从 1,536 个 96kHz 音频文件中读取数据,因此预期的数据吞吐量为(3*96000*1536) = ~421 MB/sec
,平均而言,SSD 和 CPU 可以很好地处理。在我的测试工具中,音频数据在读取后被丢弃。
但是,我的问题是关于读取延迟的。特别是,我注意到 99.99% 的读取请求(每个请求 128KB)在不到 1 毫秒的时间内得到处理,这很棒。但是,极少数读取需要更长时间(大约几毫秒),偶尔我会遇到一个非常可怕的异常值,可能需要长达 200 毫秒(!)才能完成。
我对我的程序进行了调试,建立了一个测量读取延迟的直方图,并在几个小时内报告了以下情况:
Read latencies histogram:
41358428 @ <1mS
1328 @ 1-9 mS
440 @ 10-19 mS
432 @ 20-29 mS
33 @ 30-39 mS
109 @ 40-49 mS
43 @ 50-59 mS
10 @ 60-69 mS
5 @ 70-79 mS
2 @ 80-89 mS
4 @ 90-99 mS
2 @ 100-109 mS
5 @ 130-139 mS
1 @ 140-149 mS
3 @ 150-159 mS
1 @ 170-179 mS
2 @ 180-189 mS
4 @ 190-199 mS
1 @ 200-209 mS
我的问题是,这种“长尾”行为是否是现代 NVMe SSD 驱动器的预期行为,还是非常罕见的 100+mS 延迟的存在是否表明我的硬件或软件存在问题?我不知道我是否应该接受这个现实,增加应用程序的缓冲区大小,然后继续前进,或者我是否应该尝试找出导致长读取的原因并修复它。
根据评论更新:SSD 的型号是TS2TMTE662T2-G1
,我认为这意味着它是这些。
输出自lsblk
,供参考:
root@xxxxx:~# lsblk -o NAME,FSTYPE,LABEL,MOUNTPOINT,SIZE,MODEL
NAME FSTYPE LABEL MOUNTPOINT SIZE MODEL
nvme0n1 1.9T TS2TMTE662T2-G1
|-nvme0n1p1 vfat 512M
|-nvme0n1p2 crypto_LUKS 8G
| `-rootfs_a ext4 8G
|-nvme0n1p3 crypto_LUKS 8G
| `-rootfs_b ext4 / 8G
|-nvme0n1p4 ext4 /var/log 2G
|-nvme0n1p5 ext4 /cfg 128M
`-nvme0n1p6 ext4 /udata 1.8T
答案1
通过进一步探索和测试,我发现间歇性高延迟的一个常见原因是 SSD 驱动器的垃圾收集。
具体来说,由于 NAND 闪存的工作方式,每当 SSD 固件想要写入更多数据时,它都需要一个新的(全零)闪存页面来写入数据。如果它还没有可用的闪存页面,它必须在闪存块上执行一个相当耗时的“擦除”步骤来创建一个,然后 I/O 请求才能完成。这种行为可能会导致非常高的延迟,但可以通过运行以下命令来(大部分)避免弗斯特里姆在驱动器上定期进行此操作(以便驱动器在使用时不会用尽全零页面)。
请注意,这种行为仅在驱动器被写入和读取时才会显现,并且可能还有其他原因导致偶尔出现高延迟,但我还不知道。