性能2-Docker 可能会减慢你的代码并扭曲基准测试结果

目录

Docker 可能会减慢你的代码并扭曲基准测试结果

理论上,Docker 容器没有性能开销。但实际上,它们可能会减慢你的代码并扭曲性能测量结果。

容器的好处之一是,你可以在没有虚拟化性能开销或扭曲的情况下获得一定程度的隔离。因此,Docker 镜像似乎是测量代码 CPU 性能的可重现环境的良好选择。

然而,实际情况要复杂一些。有时,在 Docker 中运行代码实际上会减慢你的代码并扭曲性能测量结果。

例如,在 macOS 和 Windows 上,标准的基于 Linux 的 Docker 容器并不是直接在操作系统上运行的,因为操作系统不是 Linux。而且,容器本身的镜像文件系统通常是通过某种覆盖文件系统挂载的,这可能会减慢速度,因此对于任何 I/O 密集型任务,你希望使用绑定挂载卷。

但即使在 Linux 上,即使是看似仅涉及 CPU 的工作负载,Docker 也可能会扭曲运行时性能。让我们看看原因以及一些解决方法。

在 Docker 中运行有时会更慢

我测试的计算机运行的是 Fedora 33,并安装了 Docker 20.10.6;我已经禁用了一些可能使基准测试不一致的操作系统和 CPU 功能(ASLR 和 turboboost)。我将比较在我的机器上运行代码和在容器中运行代码的性能,为了最大程度地模拟实际情况,我将使用 fedora:33 镜像。

首先,让我们测试一个只进行一些浮点计算的 Rust 小程序:

$ ./benchmark
Elapsed: 921ms, result: 499999999067109000
$ docker run -v $PWD:/code fedora:33 /code/benchmark
Elapsed: 915ms, result: 499999999067109000

有些运行速度较慢;我选择了最快的几次。初步看来,Docker 内外的性能似乎相同。

接下来,让我们尝试一个只进行计算操作的 Python 程序。我选择了最快的几次运行:

$ python3.9 pystone.py 
Pystone(1.2) time for 50000 passes = 0.248776
This machine benchmarks at 200984 pystones/second
$ docker run -v $PWD:/code fedora:33 python3.9 /code/pystone.py
Pystone(1.2) time for 50000 passes = 0.297675
This machine benchmarks at 167968 pystones/second

在这种情况下,使用 Docker 时 Python 性能大约慢了 16%。

更糟糕的是,我们可以看到性能下降是不一致的:我们的小型 Rust 基准测试不受 Docker 影响,但 Python 基准测试却变慢了。如果性能下降始终一致,至少在 Docker 中运行所有内容可以让我们可靠地测量相对性能,例如两个代码版本之间的性能差异。不一致的性能下降意味着 Docker 正在扭曲我们的结果。

安全的代价

容器本身并没有性能开销:关键在于,除了为网络或用户 ID 等事物提供不同的命名空间外,容器中的进程与任何其他进程一样。

那么性能下降是从哪里来的呢?一个合理的理论是,这是 Docker 的安全功能导致的。

Docker 起源于平台即服务(PaaS)的世界,其中来自不同用户的应用程序暴露在外部运行。因此,Docker 还增加了额外的安全层,以防止程序从容器逃逸到主机。

  1. 其中一种安全机制是 seccomp,Docker 使用它来限制容器可以运行的系统调用。
  2. 旧版本的 seccomp 存在性能问题,可能会减慢操作速度。
  3. Docker 仍然没有启用这个性能修复。

当然,可能还有其他 seccomp 性能问题导致了这个问题,或者 Docker 使用的其他安全机制之一,但我们可以通过以特权模式运行 Docker 容器来测试这个一般理论。这将禁用所有安全功能,因此如果这些功能是导致性能下降的原因,我们应该能够恢复速度:

$ docker run --privileged -v $PWD:/code fedora:33 python3.9 /code/pystone.py
Pystone(1.2) time for 50000 passes = 0.239254
This machine benchmarks at 208983 pystones/second

它起作用了!代码不再比主机慢。是的,我已经多次运行这两种变体:使用 --privileged 运行时,性能总是恢复正常。

更多细节:避免 --privileged 和 CPU 影响

--privileged 的问题在于它赋予了容器很多安全权限。因此,我们也可以尝试仅禁用 seccomp,这是一种不那么全面的安全降低。事实上,以下方法与 --privileged 一样有效,可以恢复性能:

$ docker run --security-opt seccomp=unconfined -v $PWD:/code fedora:33 python3.9 /code/pystone.py

进一步的搜索发现了这篇文章,指出这是为了防止 Spectre 侧信道攻击的安全措施。因此,它提供了一些更细粒度的修复建议;这也意味着在具有硬件修复功能的新 CPU 上,这可能不是问题。

简而言之,你可能会得到不同的结果,具体取决于内核版本、CPU、Docker 版本以及其他因素;请务必进行测试。

基准测试很难

那么你应该使用 --security-opt seccomp=unconfined 运行基准测试吗?也许吧。

如果你在容器化平台上运行代码,默认的 Docker 配置可能更符合实际情况。但这也可能不符合。不同的 CPU、Linux 版本、容器运行时等可能会表现不同。

你最好的选择是:在不同环境中比较测量结果,找出差异,并针对你的具体情况追求最大程度的真实性。

你可能感兴趣的:(自动化测试,docker,容器,运维)