在 docker 容器中使用 FIO 时如何绕过内存缓存?
How to bypass memory caching while using FIO inside of a docker container?
我正在尝试使用启用了 O_direct 的灵活 IO 工具来对我的主机和 docker 容器的 I/O 性能进行基准测试,以绕过内存缓存。结果非常可疑。 docker 的性能比我的主机好将近 50 倍,这是不可能的。似乎 docker 根本没有绕过缓存。即使我 运行 它与 --privileged
模式。这是我在容器内 运行 的命令,有什么建议吗?
fio --name=seqread --rw=read --direct=1 --ioengine=libaio --bs=4k --numjobs=1 --size=10G --runtime=600 --group_reporting --output-format=json >/home/docker/docker_seqread_4k.json
(请注意,这并不是一个真正的编程问题,所以 Whosebug 不是问这个问题的地方......也许 Super User or Serverfault 会是更好的选择,并能更快得到答案?)
The result is very suspicious. docker performs almost 50 times better than my host machine which is impossible. It seems like docker is not bypassing the caching at all.
如果与最坏情况的延迟相比,最好情况下的延迟小得令人怀疑,那么您的怀疑很可能是有根据的,并且内核缓存仍在进行。 Asking for O_DIRECT
is a hint not an order and the filesystem can choose to ignore it and use the cache anyway(参见 "You're asking for direct I/O to a file in a filesystem but..." 部分)。
如果您可以选择并且对磁盘速度感兴趣,最好在容器外进行任何此类测试(包含所有暗示的注意事项)。当您t/don不想禁用缓存时,另一种选择是确保您 I/O 的大小(无论是数量还是使用的区域)至少是RAM 所以大多数 I/O 不能被 buffers/cache 满足(如果你正在写 I/O 那么也做类似 end_fsync=1
的事情)。
总而言之,docker 使用的文件系统可能无法准确地执行您的请求(通过绕过缓存来测量磁盘速度,同时使用任何默认的 docker 文件系统).
为什么 Docker 基准测试可能会给出您期望的结果
Docker 引擎默认使用 OverlayFS [1][2] 驱动程序在容器中存储数据。它将图像中的所有不同层组装起来并使它们可读。写入总是写到“顶层”,即容器存储。
当对容器的文件系统执行读取和写入操作时,您将通过 Docker 的 overlay2
驱动程序、通过 OverlayFS 内核驱动程序、通过您的文件系统驱动程序(例如 ext4
) 和你的块设备。此外,由于 ,DIRECT
/O_DIRECT
只是一个提示,您正在通过的任何层可能都不会遵守。
获得更准确的结果
要在 Docker 容器中获得准确的基准测试,您应该写入卷装载或 change your storage driver to one that is not overlaid, such as the Device Mapper driver or the ZFS driver。
Device Mapper 驱动程序和 ZFS 驱动程序都需要一个专用的块设备(您可能需要一个单独的硬盘驱动器),因此使用卷装载可能是最简单的方法。
使用卷挂载
将 -v
选项与位于主机块设备上的目录一起使用。
docker run -v /absolute/host/directory:/container_mount_point alpine
使用不同的 Docker 存储驱动程序
请注意,必须在 Docker 守护程序 (dockerd
) 上更改存储驱动程序,并且不能为每个容器设置。来自 the documentation:
Important: When you change the storage driver, any existing images and containers become inaccessible. This is because their layers cannot be used by the new storage driver. If you revert your changes, you can access the old images and containers again, but any that you pulled or created using the new driver are then inaccessible.
取消免责声明后,您可以通过编辑 daemon.json
并重新启动 dockerd
来更改您的存储驱动程序。
{
"storage-driver": "devicemapper",
"storage-opts": [
"dm.directlvm_device=/dev/sd_",
"dm.thinp_percent=95",
"dm.thinp_metapercent=1",
"dm.thinp_autoextend_threshold=80",
"dm.thinp_autoextend_percent=20",
"dm.directlvm_device_force=false"
]
}
其他容器基准测试说明 - 内核
如果您尝试比较 Linux 的不同风格,请记住 Docker 在您的主机内核上仍然是 运行。
我正在尝试使用启用了 O_direct 的灵活 IO 工具来对我的主机和 docker 容器的 I/O 性能进行基准测试,以绕过内存缓存。结果非常可疑。 docker 的性能比我的主机好将近 50 倍,这是不可能的。似乎 docker 根本没有绕过缓存。即使我 运行 它与 --privileged
模式。这是我在容器内 运行 的命令,有什么建议吗?
fio --name=seqread --rw=read --direct=1 --ioengine=libaio --bs=4k --numjobs=1 --size=10G --runtime=600 --group_reporting --output-format=json >/home/docker/docker_seqread_4k.json
(请注意,这并不是一个真正的编程问题,所以 Whosebug 不是问这个问题的地方......也许 Super User or Serverfault 会是更好的选择,并能更快得到答案?)
The result is very suspicious. docker performs almost 50 times better than my host machine which is impossible. It seems like docker is not bypassing the caching at all.
如果与最坏情况的延迟相比,最好情况下的延迟小得令人怀疑,那么您的怀疑很可能是有根据的,并且内核缓存仍在进行。 Asking for O_DIRECT
is a hint not an order and the filesystem can choose to ignore it and use the cache anyway(参见 "You're asking for direct I/O to a file in a filesystem but..." 部分)。
如果您可以选择并且对磁盘速度感兴趣,最好在容器外进行任何此类测试(包含所有暗示的注意事项)。当您t/don不想禁用缓存时,另一种选择是确保您 I/O 的大小(无论是数量还是使用的区域)至少是RAM 所以大多数 I/O 不能被 buffers/cache 满足(如果你正在写 I/O 那么也做类似 end_fsync=1
的事情)。
总而言之,docker 使用的文件系统可能无法准确地执行您的请求(通过绕过缓存来测量磁盘速度,同时使用任何默认的 docker 文件系统).
为什么 Docker 基准测试可能会给出您期望的结果
Docker 引擎默认使用 OverlayFS [1][2] 驱动程序在容器中存储数据。它将图像中的所有不同层组装起来并使它们可读。写入总是写到“顶层”,即容器存储。
当对容器的文件系统执行读取和写入操作时,您将通过 Docker 的 overlay2
驱动程序、通过 OverlayFS 内核驱动程序、通过您的文件系统驱动程序(例如 ext4
) 和你的块设备。此外,由于 DIRECT
/O_DIRECT
只是一个提示,您正在通过的任何层可能都不会遵守。
获得更准确的结果
要在 Docker 容器中获得准确的基准测试,您应该写入卷装载或 change your storage driver to one that is not overlaid, such as the Device Mapper driver or the ZFS driver。 Device Mapper 驱动程序和 ZFS 驱动程序都需要一个专用的块设备(您可能需要一个单独的硬盘驱动器),因此使用卷装载可能是最简单的方法。
使用卷挂载
将 -v
选项与位于主机块设备上的目录一起使用。
docker run -v /absolute/host/directory:/container_mount_point alpine
使用不同的 Docker 存储驱动程序
请注意,必须在 Docker 守护程序 (dockerd
) 上更改存储驱动程序,并且不能为每个容器设置。来自 the documentation:
Important: When you change the storage driver, any existing images and containers become inaccessible. This is because their layers cannot be used by the new storage driver. If you revert your changes, you can access the old images and containers again, but any that you pulled or created using the new driver are then inaccessible.
取消免责声明后,您可以通过编辑 daemon.json
并重新启动 dockerd
来更改您的存储驱动程序。
{
"storage-driver": "devicemapper",
"storage-opts": [
"dm.directlvm_device=/dev/sd_",
"dm.thinp_percent=95",
"dm.thinp_metapercent=1",
"dm.thinp_autoextend_threshold=80",
"dm.thinp_autoextend_percent=20",
"dm.directlvm_device_force=false"
]
}
其他容器基准测试说明 - 内核
如果您尝试比较 Linux 的不同风格,请记住 Docker 在您的主机内核上仍然是 运行。