![启动时 Docker 磁盘读取利用率高](https://linux22.com/image/761394/%E5%90%AF%E5%8A%A8%E6%97%B6%20Docker%20%E7%A3%81%E7%9B%98%E8%AF%BB%E5%8F%96%E5%88%A9%E7%94%A8%E7%8E%87%E9%AB%98.png)
我的 Docker 服务器启动非常慢。它处于 Swarm 模式,每次服务重启(或只是服务器重启)都会占用 100% 的磁盘利用率,但启动需要大约一个小时。我尝试通过 iotop 确定是什么占用了这么多的磁盘利用率,并尝试跟踪有问题的进程。
首先,启动时它会以 100% 的利用率读取磁盘。我尝试跟踪有问题的进程,结果如下:
openat(AT_FDCWD, "/v2/var/lib/docker/image/overlay2/layerdb/sha256/321a302dc92d4265f6a28b570dfb9beb32e3ad076dbe65fa20d77d21a60533b5/descriptor.json", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "/v2/var/lib/docker/image/overlay2/layerdb/sha256/eec71f74cdd732f5ce22e6eef945367416b2fc890441926c75bf4faeb0960b87/diff", O_RDONLY|O_CLOEXEC) = 10
epoll_ctl(5, EPOLL_CTL_ADD, 10, {EPOLLIN|EPOLLOUT|EPOLLRDHUP|EPOLLET, {u32=1811274280, u64=140189543815720}}) = -1 EPERM (Operation not permitted)
epoll_ctl(5, EPOLL_CTL_DEL, 10, 0xc001c7fd94) = -1 EPERM (Operation not permitted)
fstat(10, {st_mode=S_IFREG|0644, st_size=71, ...}) = 0
read(10, "sha256:beba085e841de99407d94ef9a"..., 583) = 71
futex(0x558e5dc53010, FUTEX_WAKE_PRIVATE, 1) = 1
futex(0x558e5dc52f10, FUTEX_WAKE_PRIVATE, 1) = 1
read(10, "", 512) = 0
close(10) = 0
openat(AT_FDCWD, "/v2/var/lib/docker/image/overlay2/layerdb/sha256/eec71f74cdd732f5ce22e6eef945367416b2fc890441926c75bf4faeb0960b87/size", O_RDONLY|O_CLOEXEC) = 10
epoll_ctl(5, EPOLL_CTL_ADD, 10, {EPOLLIN|EPOLLOUT|EPOLLRDHUP|EPOLLET, {u32=1811274280, u64=140189543815720}}) = -1 EPERM (Operation not permitted)
epoll_ctl(5, EPOLL_CTL_DEL, 10, 0xc001c7fda4) = -1 EPERM (Operation not permitted)
fstat(10, {st_mode=S_IFREG|0644, st_size=5, ...}) = 0
read(10, "27039", 517) = 5
futex(0x558e5dc53010, FUTEX_WAKE_PRIVATE, 1) = 1
futex(0x558e5dc52f10, FUTEX_WAKE_PRIVATE, 1) = 1
read(10, "", 512) = 0
close(10) = 0
openat(AT_FDCWD, "/v2/var/lib/docker/image/overlay2/layerdb/sha256/eec71f74cdd732f5ce22e6eef945367416b2fc890441926c75bf4faeb0960b87/cache-id", O_RDONLY|O_CLOEXEC) = 10
epoll_ctl(5, EPOLL_CTL_ADD, 10, {EPOLLIN|EPOLLOUT|EPOLLRDHUP|EPOLLET, {u32=1811274280, u64=140189543815720}}) = -1 EPERM (Operation not permitted)
epoll_ctl(5, EPOLL_CTL_DEL, 10, 0xc001c7fda4) = -1 EPERM (Operation not permitted)
fstat(10, {st_mode=S_IFREG|0644, st_size=25, ...}) = 0
一遍又一遍地重复,针对 /v2/var/lib/docker/overlay2 中的多个文件。它看起来像是打开并尝试对 /v2/var/lib/docker/overlay2 中的每个文件进行 epoll(),但最终却失败了,因为它对普通文件描述符进行 epoll() 是一个 EPERM。这会重复很长时间,而且有时进程会停止执行此操作,另一个 dockerd 进程会恢复对磁盘的使用。在初始读取之后,容器开始启动。但是,dockerd 进程会降级为执行多次写入:
fdatasync(41) = 0
futex(0x55c22d9fd010, FUTEX_WAKE_PRIVATE, 1) = 1
pwrite64(41, "\365\17\0\0\0\0\0\0\20\0\4\0\0\0\0\0k\0\0\0\0\0\0\0\25\20\0\0\0\0\0\0"..., 4096, 16732160) = 4096
fdatasync(41) = 0
futex(0x55c22d9fd010, FUTEX_WAKE_PRIVATE, 1) = 1
pwrite64(41, "\1\0\0\0\0\0\0\0\4\0\0\0\0\0\0\0\355\332\f\355\2\0\0\0\0\20\0\0\0\0\0\0"..., 4096, 4096) = 4096
fdatasync(41) = 0
futex(0x55c22d9fd010, FUTEX_WAKE_PRIVATE, 1) = 1
pwrite64(41, "k\0\0\0\0\0\0\0\20\0\4\0\0\0\0\0\365\17\0\0\0\0\0\0\25\20\0\0\0\0\0\0"..., 4096, 438272) = 4096
fdatasync(41) = 0
futex(0x55c22d9fd010, FUTEX_WAKE_PRIVATE, 1) = 1
futex(0x55c22d9fcf10, FUTEX_WAKE_PRIVATE, 1) = 1
pwrite64(41, "\0\0\0\0\0\0\0\0\4\0\0\0\0\0\0\0\355\332\f\355\2\0\0\0\0\20\0\0\0\0\0\0"..., 4096, 0) = 4096
fdatasync(41) = 0
futex(0x55c22d9fd010, FUTEX_WAKE_PRIVATE, 1) = 1
pwrite64(41, "\365\17\0\0\0\0\0\0\20\0\4\0\0\0\0\0k\0\0\0\0\0\0\0\25\20\0\0\0\0\0\0"..., 4096, 16732160) = 4096
fdatasync(41) = 0
futex(0x55c22d9fd010, FUTEX_WAKE_PRIVATE, 1) = 1
pwrite64(41, "\1\0\0\0\0\0\0\0\4\0\0\0\0\0\0\0\355\332\f\355\2\0\0\0\0\20\0\0\0\0\0\0"..., 4096, 4096) = 4096
fdatasync(41) = 0
futex(0x55c22d9fd010, FUTEX_WAKE_PRIVATE, 1) = 1
pwrite64(41, "k\0\0\0\0\0\0\0\20\0\4\0\0\0\0\0\365\17\0\0\0\0\0\0\25\20\0\0\0\0\0\0"..., 4096, 438272) = 4096
fdatasync(41) = 0
futex(0x55c22d9fd010, FUTEX_WAKE_PRIVATE, 1) = 1
pwrite64(41, "\0\0\0\0\0\0\0\0\4\0\0\0\0\0\0\0\355\332\f\355\2\0\0\0\0\20\0\0\0\0\0\0"..., 4096, 0) = 4096
fdatasync(41) = 0
futex(0x55c22d9fd010, FUTEX_WAKE_PRIVATE, 1) = 1
pwrite64(41, "\365\17\0\0\0\0\0\0\20\0\4\0\0\0\0\0k\0\0\0\0\0\0\0\25\20\0\0\0\0\0\0"..., 4096, 16732160) = 4096
完成后,docker 命令行终于可用,并且守护进程开始通过 TCP 套接字响应。
有问题的进程的命令行是:
/usr/bin/dockerd -g /v2/var/lib/docker -H tcp://192.168.224.150:2375 -H fd:// --containerd=/run/containerd/containerd.sock
/etc/docker/daemon.json 的内容是
{
"experimental": true,
"features": { "buildkit": true },
"log-level": "warn"
}
docker container ls
在完成之前不可用(挂起)。
大多数/var/log/daemon.log
都包含如下条目:
Dec 21 16:41:48 fujitsu dockerd[622]: time="2020-12-21T16:41:48.960561732+01:00" level=info msg="NetworkDB stats fujitsu(c65b23ea0561) - netID:c9i2ol5fbrf8uz632946aovkz leaving:false netPeers:1 entries:6 Queue qLen:0 netMsg/s:0"
Dec 21 16:41:48 fujitsu dockerd[622]: time="2020-12-21T16:41:48.960570860+01:00" level=info msg="NetworkDB stats fujitsu(c65b23ea0561) - netID:r2v654bgudc9xd0492f05e5rt leaving:false netPeers:1 entries:15 Queue qLen:0 netMsg/s:0"
Dec 21 16:41:48 fujitsu dockerd[622]: time="2020-12-21T16:41:48.960579624+01:00" level=info msg="NetworkDB stats fujitsu(c65b23ea0561) - netID:nc0uqtfxfd22hf6yc2y8u7vho leaving:false netPeers:1 entries:9 Queue qLen:0 netMsg/s:0"
我已经通过将 Docker 守护进程的日志级别设置为“警告”来修复此问题,但这并没有解决读取问题。
/v2 是独立于系统分区的旋转硬盘。我注意到,清除 /v2/var/lib/docker/overlay2 可以阻止该问题至少一周的发生,但之后它又像回旋镖一样再次出现。
该服务器用作 CI 服务器,因此有大量 Docker 镜像正在那里编译,并且很少清理。这可能是罪魁祸首吗?以下是一些统计数据:
姓名 | 价值 |
---|---|
/v2/var/lib/docker/overlay2 中的文件数量 | 40993 |
/v2/var/lib/docker/overlay2/l 中的文件数量 | 40994 |
/v2/var/lib/docker/image 中的文件数量 | 328764 |
/v2/var/lib/docker 上使用的 inode | 7242204 |
/v2/var/lib/docker/overlay2 中的文件总数 | 6145533 |
/v2/var/lib/docker/overlay2 中所有文件的总大小 | 150 GB |
/v2 上使用的总空间 | 520 GB |
/v2 上只有 /v2/var/lib/docker 目录,它是 Docker 的全部使用目录。请注意,最后两个值分别是 inode 总数减去剩余目录中的文件数,以及使用的磁盘空间总量减去其他目录中的文件大小的近似值,因为在 100% 磁盘读取利用率的情况下,每个值都需要 1 小时以上的时间进行计算(为此禁用了 Docker),因为我正在运行消费级 7200 rpm SATA 驱动器,也就是说 /v2 是 2 TB Seagate Barracuda 7200.14 (AF) ST2000DM001-1ER164,目前已在线 43808 小时。这对 Docker 来说是不是太慢了?SMART 说驱动器一切正常。
我做错了什么?如何解决?我在 Debian 9 Stretch 内核 4.9.0-6-amd64 #1 SMP Debian 4.9.82-1+deb9u3 (2018-03-02) 上运行 docker-ce 5:19.03.12~3-0~debian-stretch 和 containerd.io 1.3.7-1。我早就考虑过换用 SSD。从长远来看,这样做有帮助吗?我是否应该简单地安排一个 cron 作业来清理悬空图像?还有其他人遇到过这个问题吗?
这是一个已知错误吗?我应该升级吗?