诊断 Docker for Mac 上的高 CPU 使用率

Joe*_*Joe 71 macos profiling dtrace docker

如何在 MacOS 上诊断 Docker 的原因,特别是com.docker.hyperkit使用 100% 的 CPU?

码头工人 CPU 使用率

Docker 统计信息

Docker stats 显示所有正在运行的容器都具有较低的 CPU、内存、网络 IO 和块 IO。

码头工人统计输出

iosnoop

iosnoop 显示com.docker.hyperkit每秒对文件执行大约 50 次写入,总计每秒 500KB Docker.qcow2。根据什么是 Docker.qcow2?,Docker.qcow2是一个稀疏文件,是所有 Docker 容器的持久存储。

在我的情况下,文件不是那么稀疏。物理大小与逻辑大小相匹配。

docker.qcow 实际大小

dtrace (dtruss)

dtrusssudo dtruss -p $DOCKER_PID显示大量psynch_cvsignalpsynch_cvwait调用。

psynch_cvsignal(0x7F9946002408, 0x4EA701004EA70200, 0x4EA70100)          = 257 0
psynch_mutexdrop(0x7F9946002318, 0x5554700, 0x5554700)           = 0 0
psynch_mutexwait(0x7F9946002318, 0x5554702, 0x5554600)           = 89474819 0
psynch_cvsignal(0x10BF7B470, 0x4C8095004C809600, 0x4C809300)             = 257 0
psynch_cvwait(0x10BF7B470, 0x4C8095014C809600, 0x4C809300)               = 0 0
psynch_cvwait(0x10BF7B470, 0x4C8096014C809700, 0x4C809600)               = -1 Err#316
psynch_cvsignal(0x7F9946002408, 0x4EA702004EA70300, 0x4EA70200)          = 257 0
psynch_cvwait(0x7F9946002408, 0x4EA702014EA70300, 0x4EA70200)            = 0 0
psynch_cvsignal(0x10BF7B470, 0x4C8097004C809800, 0x4C809600)             = 257 0
psynch_cvwait(0x10BF7B470, 0x4C8097014C809800, 0x4C809600)               = 0 0
psynch_cvwait(0x10BF7B470, 0x4C8098014C809900, 0x4C809800)               = -1 Err#316
Run Code Online (Sandbox Code Playgroud)

更新:top在 Docker 主机上

/sf/answers/4080526831/

docker run -it --rm --pid host busybox top
Run Code Online (Sandbox Code Playgroud)

docker 嵌入式主机上的 CPU 使用率约为 3%。我的 MacBook 上的 CPU 使用率约为 100%。因此,docker 嵌入式主机不会导致 CPU 使用率飙升。

码头主机顶部

更新:运行最常见堆栈跟踪的 dtrace 脚本

来自以下答案中 dtrace 脚本的堆栈跟踪:https : //stackoverflow.com/a/58293035/30900

这些内核堆栈跟踪看起来无害。

              AppleIntelLpssGspi`AppleIntelLpssGspi::regRead(unsigned int)+0x1f
              AppleIntelLpssGspi`AppleIntelLpssGspi::transferMmioDuplexMulti(void*, void*, unsigned long long, unsigned int)+0x91
              AppleIntelLpssSpiController`AppleIntelLpssSpiController::transferDataMmioDuplexMulti(void*, void*, unsigned int, unsigned int)+0xb2
              AppleIntelLpssSpiController`AppleIntelLpssSpiController::_transferDataSubr(AppleInfoLpssSpiControllerTransferDataRequest*)+0x5bc
              AppleIntelLpssSpiController`AppleIntelLpssSpiController::_transferData(AppleInfoLpssSpiControllerTransferDataRequest*)+0x24f
              kernel`IOCommandGate::runAction(int (*)(OSObject*, void*, void*, void*, void*), void*, void*, void*, void*)+0x138
              AppleIntelLpssSpiController`AppleIntelLpssSpiDevice::transferData(IOMemoryDescriptor*, void*, unsigned long long, unsigned long long, IOMemoryDescriptor*, void*, unsigned long long, unsigned long long, unsigned int, AppleIntelSPICompletion*)+0x151
              AppleHSSPISupport`AppleHSSPIController::transferData(IOMemoryDescriptor*, void*, unsigned long long, unsigned long long, IOMemoryDescriptor*, void*, unsigned long long, unsigned long long, unsigned int, AppleIntelSPICompletion*)+0xcc
              AppleHSSPISupport`AppleHSSPIController::doSPITransfer(bool, AppleHSSPITransferRetryReason*)+0x97
              AppleHSSPISupport`AppleHSSPIController::InterruptOccurred(IOInterruptEventSource*, int)+0xf8
              kernel`IOInterruptEventSource::checkForWork()+0x13c
              kernel`IOWorkLoop::runEventSources()+0x1e2
              kernel`IOWorkLoop::threadMain()+0x2c
              kernel`call_continuation+0x2e
               53

              kernel`waitq_wakeup64_thread+0xa7
              pthread`__psynch_cvsignal+0x495
              pthread`_psynch_cvsignal+0x28
              kernel`psynch_cvsignal+0x38
              kernel`unix_syscall64+0x27d
              kernel`hndl_unix_scall64+0x16
               60

              kernel`hndl_mdep_scall64+0x4
              113

              kernel`ml_set_interrupts_enabled+0x19
              524

              kernel`ml_set_interrupts_enabled+0x19
              kernel`hndl_mdep_scall64+0x10
             5890

              kernel`machine_idle+0x2f8
              kernel`call_continuation+0x2e
            43395
Run Code Online (Sandbox Code Playgroud)

用户空间中超过 17 秒的最常见堆栈跟踪显然暗示 com.docker.hyperkit。在 17 秒内有 1365 个堆栈跟踪,其中com.docker.hyperkit创建了平均每秒 80 个线程的线程。

              com.docker.hyperkit`0x000000010cbd20db+0x19f9
              com.docker.hyperkit`0x000000010cbdb98c+0x157
              com.docker.hyperkit`0x000000010cbf6c2d+0x4bd
              libsystem_pthread.dylib`_pthread_body+0x7e
              libsystem_pthread.dylib`_pthread_start+0x42
              libsystem_pthread.dylib`thread_start+0xd
               19

              Hypervisor`hv_vmx_vcpu_read_vmcs+0x1
              com.docker.hyperkit`0x000000010cbd4c4f+0x2a
              com.docker.hyperkit`0x000000010cbd20db+0x174a
              com.docker.hyperkit`0x000000010cbdb98c+0x157
              com.docker.hyperkit`0x000000010cbf6c2d+0x4bd
              libsystem_pthread.dylib`_pthread_body+0x7e
              libsystem_pthread.dylib`_pthread_start+0x42
              libsystem_pthread.dylib`thread_start+0xd
               22

              Hypervisor`hv_vmx_vcpu_read_vmcs
              com.docker.hyperkit`0x000000010cbdb98c+0x157
              com.docker.hyperkit`0x000000010cbf6c2d+0x4bd
              libsystem_pthread.dylib`_pthread_body+0x7e
              libsystem_pthread.dylib`_pthread_start+0x42
              libsystem_pthread.dylib`thread_start+0xd
               34

              com.docker.hyperkit`0x000000010cbd878d+0x36
              com.docker.hyperkit`0x000000010cbd20db+0x42f
              com.docker.hyperkit`0x000000010cbdb98c+0x157
              com.docker.hyperkit`0x000000010cbf6c2d+0x4bd
              libsystem_pthread.dylib`_pthread_body+0x7e
              libsystem_pthread.dylib`_pthread_start+0x42
              libsystem_pthread.dylib`thread_start+0xd
               47

              Hypervisor`hv_vcpu_run+0xd
              com.docker.hyperkit`0x000000010cbd20db+0x6b6
              com.docker.hyperkit`0x000000010cbdb98c+0x157
              com.docker.hyperkit`0x000000010cbf6c2d+0x4bd
              libsystem_pthread.dylib`_pthread_body+0x7e
              libsystem_pthread.dylib`_pthread_start+0x42
              libsystem_pthread.dylib`thread_start+0xd
              135
Run Code Online (Sandbox Code Playgroud)

相关问题

Github - docker /for-mac: com.docker.hyperkit 100% cpu 使用率又回来了 #3499 。一条评论建议添加此处描述的卷缓存:https : //www.docker.com/blog/user-guided-caching-in-docker-for-mac/。我试过了,CPU 使用率降低了约 10%。

Chr*_*ams 30

我也有同样的问题。删除所有卷后,我的 CPU % 恢复正常。

docker system prune --volumes
Run Code Online (Sandbox Code Playgroud)

我还手动删除了一些命名卷:

docker volume rm NameOfVolumeHere
Run Code Online (Sandbox Code Playgroud)

这并不能解决无法在 Docker for mac 中使用卷的整体问题。现在我只是在注意我使用的卷数量并在不使用时关闭 Docker 桌面。

  • 救了我的培根。做得好。macOS 大苏尔 (3认同)

BMi*_*tch 12

我怀疑这个问题与 IO 相关。对于 MacOS 卷,这涉及 osxfs,您可以在其中执行一些性能调整。主要是,如果您可以接受较少的一致性检查,您可以将卷模式设置delegated为更快的性能。有关更多详细信息,请参阅文档:https : //docs.docker.com/docker-for-mac/osxfs-caching/。但是,如果您的图像包含大量小文件,则性能会受到影响,尤其是当您还有很多图像层时。

您还可以尝试使用以下命令来调试 docker 使用的嵌入式 VM 中的任何进程问题:

docker run -it --rm --pid host busybox top
Run Code Online (Sandbox Code Playgroud)

(要退出,请使用<ctrl>-c


要跟踪是否是 IO,您还可以尝试以下操作:

$ docker run -it --rm --pid host alpine /bin/sh
$ apk add sysstat
$ pidstat -d 5 12
Run Code Online (Sandbox Code Playgroud)

这将在 VM pid 命名空间中运行的 alpine 容器内运行,显示任何进程发生的任何 IO,无论该进程是否在容器内。统计数据是每 5 秒一分钟(12 次),然后它会为您提供每个进程的平均表。然后您可以<ctrl>-d销毁高山容器。


从评论和编辑中,这些统计数据可能会检查出来。一个 4 核 MBP 有 8 个线程,所以如果 MacOS 报告的与其他基于 Unix 的系统相同,那么 CPU 的完整利用率应该是 800%。在 VM 内部,top 命令中显示过去一分钟的平均负载超过 100%(尽管低于 5 和 15 的平均值),这与您在主机上看到的 hyperkit 进程大致相同。由于您需要添加系统和用户百分比,因此瞬时使用率超过 12%,而不是 3%。pidstat 中显示的 IO 数字与您看到的写入 qcow2 映像的内容大致一致。


如果 docker 引擎本身正在颠簸(例如,重新启动容器,或运行大量健康检查),那么您可以通过查看以下输出来调试:

docker events
Run Code Online (Sandbox Code Playgroud)

  • 使用“pidstat”进行更新以更好地跟踪 IO 问题。 (2认同)

Bra*_*rks 10

编辑:几周后,我的CPU问题又回来了 - 所以下面的解决方案可能不值得

我的 CPU 总是运行得非常高,而且这不是 I/O,正如使用确定的那样docker stats

我做了很多事情,但在做了以下操作后,它突然下降到合理水平并保持这种状态一个多星期了:

  • 确保您拥有正确的 CPU 数量 - 不是您拥有的数量,而是该数量的一半。我的超过一半,我觉得这是真正的问题,在Preferences | Resources
  • 如果可能,减少文件共享数量 - Preferences | Resources、/private、/tmp/、/var/folders
  • 禁用use gRPC FUSE for file sharing-Preferences | Resources


And*_*nle 6

这是一个小的 dTrace 脚本,我用它来查找内核在哪里花费了时间(它来自 Solaris,可以追溯到 Solaris 10 的早期):

#!/usr/sbin/dtrace -s

profile:::profile-1001hz
/arg0/
{
    @[ stack() ] = count();
}
Run Code Online (Sandbox Code Playgroud)

它只是对内核堆栈跟踪进行采样,并对聚合中遇到的每一个进行计数@

以 root 身份运行:

... # ./kernelhotspots.d > /tmp/kernel_hot_spots.txt
Run Code Online (Sandbox Code Playgroud)

当您遇到 CPU 问题时,让它运行相当长的时间,然后点击CTRL-C以中断脚本。它将发出它遇到的所有内核堆栈跟踪,最常见的是最后一个。如果您需要更多(或更少)默认堆栈帧

    @[ stack( 15 ) ] = count();
Run Code Online (Sandbox Code Playgroud)

这将显示 15 个调用深度的堆栈帧。

最后几个堆栈跟踪将是您的内核花费大部分时间的地方。这可能会或可能不会提供信息。

该脚本将对用户空间堆栈跟踪执行相同的操作:

#!/usr/sbin/dtrace -s

profile:::profile-1001hz
/arg1/
{
    @[ ustack() ] = count();
}
Run Code Online (Sandbox Code Playgroud)

类似地运行它:

... # ./userspacehotspots.d > /tmp/userspace_hot_spots.txt
Run Code Online (Sandbox Code Playgroud)

ustack()有点慢 - 为了发出实际的函数名称,dTrace 必须做更多的工作才能从适当进程的地址空间获取它们。

禁用系统完整性保护可能会帮助您获得更好的堆栈跟踪。

有关更多详细信息,请参阅DTrace 操作基础知识。

  • 谢谢,我用脚本的结果更新了问题。用户空间堆栈跟踪显示 com.docker.hyperkit 创建了很多线程。 (2认同)

小智 5

更改卷以使用委派配置对我有用,并导致 CPU 使用率急剧下降。查看文档:https : //docs.docker.com/docker-for-mac/osxfs-caching/#delegated

如何在我的 docker-compose.yml 中设置:

version: "3"
services: 
  my_service:
    image: python3.6
    ports:
      - "80:10000"
    volumes:
      - ./code:/www/code:cached
Run Code Online (Sandbox Code Playgroud)

对我来说这行得通,macOS 10.15.5,Docker Desktop 2.3.0