诊断适用于Mac的Docker上的CPU使用率高

时间:2019-10-07 22:13:01

标签: macos docker profiling dtrace

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

docker CPU usage

Docker统计信息

Docker统计数据显示所有正在运行的容器的CPU,内存,网络IO和块IO均较低。

docker stats output

iosnoop

iosnoop显示com.docker.hyperkit每秒执行约50次写入文件Docker.qcow2的操作,总计每秒500KB。根据{{​​3}},Docker.qcow2是一个稀疏文件,是所有Docker容器的持久存储。

就我而言,文件不是那么稀疏。物理大小与逻辑大小匹配。

What is Docker.qcow2?

dtrace(dtruss)

dtruss sudo 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

更新:top在Docker主机上

来自docker.qcow actual size

docker run -it --rm --pid host busybox top

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

https://stackoverflow.com/a/58293240/30900

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

来自以下答案中dtrace脚本的堆栈跟踪:docker host top

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

              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

17秒内用户空间中最常见的堆栈跟踪明确暗示了com.docker.hyperkit。 com.docker.hyperkit在17秒内创建了1365个堆栈跟踪,其中 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 创建了平均每秒80个线程的线程。

const initialState = {
  allIds:[],
  byId:{},
};

const allIds = (state = initialState.allIds, action) => {
  switch (action.type) {
    case  FETCH_IMAGES_SUCCESS:
      return action.images.reduce((nextState, image) => {
        if (nextState.indexOf(image.id) === -1) {
          nextState.push(image.id);
        }
        return nextState;
      }, [...state]);
      case UPLOAD_IMAGE_SUCCESS:
        console.log(action.data)
        return [action.data.id, ...state];

      case POST_COMMENT_SUCCESS:
        console.log(action)
        return [action.data.id, ...state];
    default:
      return state;
  }
}
const image = (state = {}, action) => {
  switch (action.type) {
    case POST_COMMENT_SUCCESS:
      return [...state.comments, action.data, ...state.comments]

    default:
      return state;
  }
}

const byId = (state = initialState.byId, action) => {
  switch (action.type) {
    case FETCH_IMAGES_SUCCESS:
      return action.images.reduce((nextState, image) => {
        nextState[image.id] = image;

        return nextState;
      }, {...state});
    case POST_COMMENT_SUCCESS:
      console.log(action.data) // renders new commnent
      return {
        ...state,
        ...state.comments,
        [action.data.id]: action.data,

      }
    case UPLOAD_IMAGE_SUCCESS:
      console.log(action)
      return {
        ...state,
        [action.data.id]: action.data,
      };
    default:
      return state;
  }
}

相关问题

Github-docker / for-mac:https://stackoverflow.com/a/58293035/30900。有一条评论建议添加此处描述的卷缓存:com.docker.hyperkit 100% cpu usage is back again #3499 。我尝试了一下,CPU使用率降低了约10%。

7 个答案:

答案 0 :(得分:2)

更改卷以使用委派配置对我来说很有效,并且导致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

对于我来说,这是可行的,macOS 10.15.5,Docker Desktop 2.3.0

答案 1 :(得分:1)

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

#!/usr/sbin/dtrace -s

profile:::profile-1001hz
/arg0/
{
    @[ stack() ] = count();
}

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

以root身份运行

... # ./kernelhotspots.d > /tmp/kernel_hot_spots.txt

在遇到CPU问题时,让它运行相当长的一段时间,然后按CTRL-C断开脚本。它将发出所有遇到的内核堆栈跟踪信息,这是最常见的最后一个。如果您需要使用默认值的更多(或更少)堆栈帧,请使用

    @[ stack( 15 ) ] = count();

这将显示一个堆栈框架,其深度为15个调用。

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

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

#!/usr/sbin/dtrace -s

profile:::profile-1001hz
/arg1/
{
    @[ ustack() ] = count();
}

类似地运行它:

... # ./userspacehotspots.d > /tmp/userspace_hot_spots.txt

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

Disabling System Integrity Protection可能会帮助您获得更好的堆栈跟踪。

有关更多详细信息,请参见DTrace Action Basics

答案 2 :(得分:1)

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

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

docker run -it --rm --pid host busybox top

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


要确定是否是IO,还可以尝试以下操作:

$ docker run -it --rm --pid host alpine /bin/sh
$ apk add sysstat
$ pidstat -d 5 12

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


从评论和编辑中,这些统计信息可能会签出。 4核MBP具有8个线程,因此,如果MacOS报告与其他基于Unix的系统相同,则CPU的总利用率应为800%。在虚拟机内部,过去一分钟的平均值显示在top命令中的负载超过100%(尽管低于5和15的平均值),这与主机上的hyperkit进程大致相同。由于您需要添加系统百分比和用户百分比,因此瞬时使用率最高时超过12%,而不是3%。并且pidstat中显示的IO编号与您看到的写入qcow2映像的大致一致。


如果Docker引擎本身发生故障(例如,重新启动容器或运行大量运行状况检查),则可以通过观察以下输出来调试它:

docker events

答案 3 :(得分:0)

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

docker system prune --volumes

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

docker volume rm NameOfVolumeHere

这不能解决无法在Mac的Docker上使用卷的整体问题。现在,我只是在小心我使用的卷数量,并在不使用时关闭Docker桌面。

答案 4 :(得分:0)

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

我的 CPU 总是运行得非常快,而不是 I/O,这是使用 docker stats

确定的

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

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

答案 5 :(得分:0)

禁用 use gRPC FUSE for file sharing 可能不是一个好主意。我从 docker 社区提出的另一个问题中找到了反馈。见下图:


So we'll look into that. However, 
osxfs will not be supported long term. 
We can't maintain two solutions.

hier to docker issue thread

答案 6 :(得分:-1)

就我而言,我有一个 MBP 2017,它是双核,但我的 docker 设置为使用 4 个 cpu,这导致 CPU 运行如此之高,我通过将 cpu 减少到 1 个核来修复它

enter image description here