为什么使用 O_DIRECT 标志时读取速度更快?

Abd*_*ood 5 linux bandwidth read-only benchmark fio

我在 SSD 中复制了一个 10GB 的文件,使用 fio 命令进行基准测试,其读取带宽约为 3.3GB/s。这是参考: https: //cloud.google.com/compute/docs/disks/benchmarking-pd-performance

我使用“sync; echo 3 > /proc/sys/vm/drop_caches”清除了缓存。之后,我尝试每次使用系统调用 open() 和 read() 以 3MB 的小块读取文件。如果我打开没有 O_DIRECT 和 O_SYNC 的文件,它会给我大约 1.2GB/s 的带宽。但是,如果我使用 O_DIRECT 和 O_SYNC,它会提供大约 3GB/s 的带宽。即使 O_DIRECT 也没有真正使用页面缓存,两次都会清除缓存。

我的问题是为什么 O_DIRECT 提供正常的 IO 带宽,而没有 O_DIRECT 我无法获得它。由于从 IO 到页面缓存的数据带宽为 3.3GB/s,从页面缓存到用户缓冲区的带宽假设约为 7GB/si。该管道还应提供正常的 3.3GB/s。为什么速度比较慢?

我每次都会读新的 3MB。我没有重用数据,因此缓存并不是很有用。但是管道应该是受IO约束的,为什么不呢?

CPU 为 Intel(R) Xeon(R) Silver 4214 CPU @ 2.20GHz。我不确定 DRAM 的速度。但问题是,如果我多次重新读取相同的 3MB,那么我会获得约 8GB/s 的带宽。我想这应该是 DRAM 带宽。因为linux可以使用所有的空闲RAM作为页面缓存。

更新

我尝试了启用和不启用 O_DIRECT 的 fio 命令并记录了 iostat。

使用这个 fio 命令。“fio --name=read_throughput --directory=$TEST_DIR --numjobs=1 --size=10G --time_based --runtime=30s --ramp_time=0s --ioengine=sync --direct=0 --verify= 0 --bs=4K --io深度=1 --rw=读取 --group_reporting=1 --io深度_batch_submit=64 --io深度_batch_complete_max=64"

用了这个iostat。

“iostat -j ID nvme0c0n1 -x 1”

我得出以下结论,无论使用的块大小如何,没有 O_DIRECT 标志的单线程读取都无法通过足够的读取请求使 SSD 饱和以实现 3.3GB/s。然而,使用 O_DIRECT falg,当块大小为 64M 或更大时,单线程读取能够使设备饱和。3M 时约为 2.7GB/s。

现在的问题是,为什么没有 O_DIRECT 标志,CPU 无法向 SSD 发送足够的读取请求,为什么它会限制它们?这与缓存管理限制有关吗?如果是,哪个参数限制它?我可以更改它并查看它是否会影响发送到设备的读取请求量?

Gra*_*ell 2

O_DIRECT 比一般读取更快,因为它绕过操作系统的缓冲区。您正在直接从驱动器读取。有几个原因可能会更快,但请记住,在这个级别上,事情会变得非常具体。我所说的设置特定因素的示例:如果您有一个针对 NAND 与 4kB 块内的 8kB 写入进行优化的驱动器,并且您以错误的大小写入/读取,您将看到一半的性能,但这需要您有一个内部了解驱动器的工作原理。这甚至可能在同一型号中有所不同 - 例如:驱动器的 A 型号可能与驱动器的相同 B 型号具有不同的优化(我在现场多次看到过这种情况)

但回到你的问题:

  1. 无需复制进出的缓存
  2. 如果您正在做类似 FIO 的事情,您将获得更可预测的读取行为
  3. 1MB 是一个很大的块大小,因此您将因不处理缓存而获得额外的好处

除此之外,您必须开始更深入地进行基准测试,这是一个非常复杂的主题。

我的一般建议是从 开始io_stat。高avgqu-sz?接近util100%,如果您接近驱动器的最大容量,则可能会如此。等待时间长吗?你有RAID吗?您选择了什么调度算法?我见过的导致这类事情的原因有很多,要弄清楚到底是什么原因导致了哪些行为对于您的特定系统来说将是非常独特的。

我一开始所说的可能会让你大致了解。最好的猜测是,如果您正在进行大块读取,您会因某种缓存效率低下而节省成本。