bigywater.tech
Docker · 25

OverlayFS 的 copy-up:修改一个大文件第一次写入有多慢

容器改动镜像里的一个大文件,第一次写入为什么会卡一下?这篇用 128 MiB 的文件实测 copy-up:读、追加、只改权限各要多久,upperdir 里多了什么,以及数据放在 volume 里有什么不同。

155.0~2174.1 ms
第 1 次往镜像里 128 MiB 文件追加 1 字节的耗时范围(3 次),第 2 次起约 0 ms
chmod 也要复制
只改权限也让 128 MiB 的文件整个复制进 upperdir(179.6~862.0 ms)
0.0 ms
同样的文件在 volume 里追加 1 字节

第一次写

实测 · 本机执行输出
  读 big1.bin 的 1 字节:0.1 / 0.1 / 0.1 ms(3 个新容器各跑一次;中位数 0.1 ms)
  第 1 次往 big1.bin 追加 1 字节:2174.1 / 242.7 / 155.0 ms(3 个新容器各跑一次;中位数 242.7 ms)
  第 2 次往 big1.bin 追加 1 字节:0.1 / 0.0 / 0.0 ms(3 个新容器各跑一次;中位数 0.0 ms)
  第 3 次往 big1.bin 追加 1 字节:0.6 / 0.0 / 0.0 ms(3 个新容器各跑一次;中位数 0.0 ms)
  对没碰过的 big2.bin 只做 chmod:862.0 / 309.0 / 179.6 ms(3 个新容器各跑一次;中位数 309.0 ms)
  往 small.txt(1 KB)追加 1 字节:8.7 / 4.1 / 3.7 ms(3 个新容器各跑一次;中位数 4.1 ms)
  新建并写入 128 MiB 的新文件(含 fsync):3744.2 / 999.6 / 935.1 ms(3 个新容器各跑一次;中位数 999.6 ms)

读文件不会触发复制(0.1 ms)。第一次往 128 MiB 的文件追加 1 字节,三个新容器分别花了 2174.1、242.7、155.0 ms;随后再追加只要约 0 ms。三次数字差别很大,这台机器上同时还跑着别的容器,我没有隔离干扰,所以别把某个绝对值当成基准,看量级和“只有第一次慢”这个现象。

只对 big2.bin 做 chmod,也要 179.6~862.0 ms;往 1 KB 的小文件追加只要几毫秒。这个版本的 overlay 在元数据改动时也复制整个文件(见 upperdir 里 big2.bin 是完整的 134217728 字节);是否有 metacopy 之类的选项能避免,我没有测。

upperdir 里是什么

实测 · 本机执行输出
  upperdir 里的文件(最后一个容器):134217731 ./data/big1.bin ; 134217728 ./data/big2.bin ; 1025 ./data/small.txt ; 134217728 ./new.bin ; 5781 ./usr/local/lib/python3.12/encodings/__pycache__/__init__.cpython-312.pyc ; 12414 ./usr/local/lib/python3.12/encodings/__pycache__/aliases.cpython-312.pyc ; 2153 ./usr/local/lib/python3.12/encodings/__pycache__/utf_8.cpython-312.pyc
  big1.bin 在 upperdir 里的大小 = 134217731 字节(原来 134217728,追加了 3 字节);big2.bin 做了 chmod 后 = 134217728 字节

big1.bin 的大小是 134217731 字节,整个文件都在 upperdir 里;改动 1 字节占用了 128 MiB 的可写层空间。镜像里有大文件又要频繁改的程序(比如数据库文件)不要放在镜像层里。

用 volume

实测 · 本机执行输出
  volume 里的 big1.bin 第 1 次追加 1 字节: 0.0 ms

把大文件放在 volume 里,追加 1 字节是 0.0 ms,因为 volume 不是镜像的层。这个对比没有测 volume 的读写吞吐,只说明没有 copy-up。

分步演示

copy-up 的代价
本步的对象

    本文用到的工具与边界

    • 本机 macOS 27 arm64 / Docker Desktop(Engine 29.8.2,容器跑在 Docker Desktop 自带的 Linux 虚拟机里,内核与宿主机的 macOS 不同);镜像为 linux/arm64;需要看虚拟机内部时用特权容器 + nsenter;计时用 time / date +%s%N,数字每次运行会有小幅抖动。基础镜像 python:3.12-alpine,脚本用 time.perf_counter 在容器内计时;每个场景用 3 个新容器各测一次并列出全部数值(没有取平均);文件内容是 os.urandom 随机数据;机器上同时有其它容器在运行,数字抖动大;实验后已删除镜像、容器和 volume
    • 没有验证:经典 overlay2 驱动、metacopy 选项、更大的文件(GB 级)、volume 的真实吞吐、reflink / 其它文件系统的行为、目录 rename 的代价
    京ICP备2026067502号-1京公网安备11010502063487号