1

I am trying to benchmark I/O performance on my host and docker container using flexible IO tool with O_direct enabled in order to bypass memory caching. 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. even if I ran it with --privileged mode. This is the command I ran inside of a container, Any suggestions?

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
gqli
  • 985
  • 3
  • 11
  • 34

2 Answers2

3

(Note this isn't really a programming question so Stackoverflow is the wrong place to ask this... Maybe Super User or Serverfault would be a better choice and get faster answers?)

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.

If your best case latencies are suspiciously small compared to your worst case latencies it is highly likely your suspicions are well founded and that kernel caching is still happening. Asking for O_DIRECT is a hint not an order and the filesystem can choose to ignore it and use the cache anyway (see the part about "You're asking for direct I/O to a file in a filesystem but...").

If you have the option and you're interested in disk speed, it is better to do any such test outside of a container (with all the caveats that implies). Another option when you can't/don't want to disable caching is ensure that you do I/O that is at least two to three times the size (both in terms of amount and the region being used) of RAM so the majority of I/O can't be satisfied by buffers/cache (and if you're doing write I/O then do something like end_fsync=1 too).

In summary, the filesystem being used by docker may make it impossible to accurately do what you're requesting (measure the disk speed by bypassing cache while using whatever your default docker filesystem is).

Anon
  • 6,306
  • 2
  • 38
  • 56
  • O_DIRECT on a block device isn't optional/ignoreable, is it? (I'd expect an error on open if it wasn't supported, but I haven't tried it.) IDK if that would help the OP any. – Peter Cordes Feb 17 '20 at 08:35
  • 1
    @PeterCordes Hmm I think that would depend on the block device (e.g. I don't know what happens on ramfs devices) but if you mean "regular" local disk devices I would say you're correct. – Anon Feb 17 '20 at 12:03
1

Why a Docker benchmark may give the results you expect

The Docker engine uses, by default, the OverlayFS [1][2] driver for data storage in a containers. It assembles all of the different layers from the images and makes them readable. Writing is always done to the "top" layer, which is the container storage.

When performing reads and writes to the container's filesystem, you're passing through Docker's overlay2 driver, through the OverlayFS kernel driver, through your filesystem driver (e.g. ext4) and onto your block device. Additionally, as Anon mentioned, DIRECT/O_DIRECT is just a hint, and may not be respected by any of the layers you're passing through.

Getting more accurate results

To get an accurate benchmarks within a Docker container, you should write to a volume mount or change your storage driver to one that is not overlaid, such as the Device Mapper driver or the ZFS driver. Both the Device Mapper driver and the ZFS driver require a dedicated block device (you'll likely need a separate hard drive), so using a volume mount might be the easiest way to do this.

Use a volume mount

Use the -v options with a directory that sits on a block device on your host.

docker run -v /absolute/host/directory:/container_mount_point alpine

Use a different Docker storage driver

Note that the storage driver must be changed on the Docker daemon (dockerd) and cannot be set per container. From 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.

With that disclaimer out of the way, you can change your storage driver by editing daemon.json and restarting 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"
  ]
}

Additional container benchmark notes - kernel

If you are trying to compare different flavors of Linux, keep in mind that Docker is still running on your host machine's kernel.

Codebling
  • 10,764
  • 2
  • 38
  • 66