[macos] Docker for Mac에서 높은 CPU 사용량 진단

MacOS에서 Docker의 원인, 특히 com.docker.hyperkitCPU를 100 % 사용 하는 원인을 어떻게 진단 합니까?

도커 CPU 사용량

도커 통계

Docker 통계는 실행중인 모든 컨테이너에 CPU, 메모리, net IO 및 블록 IO가 낮음을 보여줍니다.

도커 통계 출력

iosnoop

iosnoop은 com.docker.hyperkit파일에 초당 총 500KB의 초당 약 50 개의 쓰기 를 수행 하는 것을 보여줍니다 Docker.qcow2. 에 따르면 Docker.qcow2 무엇입니까? , Docker.qcow2모든 도커 용기에 대한 영구 저장소의 스파 스 파일입니다.

제 경우에는 파일이 그 스파 스가 아닙니다. 물리적 크기는 논리적 크기와 일치합니다.

docker.qcow 실제 크기

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

업데이트 : topDocker 호스트에서

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

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

docker 내장 호스트의 CPU 사용량은 ~ 3 %입니다. MacBook의 CPU 사용량은 ~ 100 %입니다. 따라서 도커 내장 호스트로 인해 CPU 사용량이 급증하지 않습니다.

도커 호스트 상단

업데이트 : 가장 일반적인 스택 추적의 dtrace 스크립트 실행

https://stackoverflow.com/a/58293035/30900 에서 dtrace 스크립트의 추적을 추적 하십시오 .

이 커널 스택 추적은 무해 해 보입니다.

              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과 관련이 있습니다. 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

관련 문제

Github-docker / for-mac : com.docker.hyperkit 100 % CPU 사용량이 다시 # 3499로 돌아 왔습니다
. 한 의견은 https://www.docker.com/blog/user-guided-caching-in-docker-for-mac/에 설명 된 볼륨 캐싱 추가를 제안 합니다. 나는 이것을 시도하고 CPU 사용량이 ~ 10 % 감소했습니다.



답변

나는 같은 문제를 가지고있다. 모든 볼륨을 제거한 후 CPU %가 정상으로 돌아갔습니다.

docker system prune --volumes

또한 일부 명명 된 볼륨을 수동으로 제거했습니다.

docker volume rm NameOfVolumeHere

Docker for mac에서 볼륨을 사용할 수 없다는 전반적인 문제는 해결되지 않습니다. 지금은 사용중인 볼륨의 양에주의하고 Docker 데스크탑을 사용하지 않을 때 닫는 중입니다.


답변

문제는 IO와 관련이 있다는 것입니다. MacOS 볼륨의 경우 여기에는 수행 할 수있는 성능 조정이있는 osxfs가 포함됩니다. 기본적으로 일관성 검사를 적게받을 수있는 경우 delegated성능을 높이기 위해 볼륨 모드를 설정할 수 있습니다 . 자세한 내용은 문서를 참조하십시오 : https://docs.docker.com/docker-for-mac/osxfs-caching/ . 그러나 이미지에 많은 수의 작은 파일이 포함 된 경우 특히 이미지 레이어가 많은 경우 성능이 저하됩니다.

도 커가 사용하는 내장 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를 표시합니다. 통계는 1 분 (12 회) 동안 5 초마다이며 프로세스 당 평균 테이블을 제공합니다. 그런 다음 <ctrl>-d알파인 컨테이너를 파괴 할 수 있습니다 .


의견 및 수정 사항에서 이러한 통계를 확인할 수 있습니다. 4 코어 MBP에는 8 개의 스레드가 있으므로 MacOS가 다른 Unix 기반 시스템과 동일하게보고하는 경우 전체 CPU 사용률은 800 % 여야합니다. VM 내부에는 지난 분 평균 (5 및 15 평균보다 적음)의 최상위 명령에 100 % 이상의로드가 표시되어 호스트의 하이퍼 킷 프로세스에 대해 대략적으로 볼 수 있습니다. 시스템 및 사용자 백분율을 추가해야하므로 즉각적인 사용량은 3 %가 아니라 12 % 이상입니다. 그리고 pidstat에 표시된 IO 번호는 qcow2 이미지에 기록 된 것과 대략 일치합니다.


도커 엔진 자체가 스 래싱하는 경우 (예 : 컨테이너 다시 시작 또는 많은 상태 확인 실행) 다음의 출력을보고이를 디버깅 할 수 있습니다.

docker events


답변

이것은 커널이 시간을 보내는 곳을 찾는 데 사용하는 작은 dTrace 스크립트입니다 (Solaris에서 왔으며 Solaris 10의 초기 시절로 거슬러 올라갑니다).

#!/usr/sbin/dtrace -s

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

단순히 커널 스택 추적을 샘플링하고 @hot집계 에서 발생하는 각 추적을 계산합니다 .

루트로 실행하십시오.

... # ./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는 실제 함수 이름을 내보내려면 적절한 프로세스의 주소 공간에서 더 많은 작업을 수행해야합니다.

시스템 무결성 보호를 비활성화 하면 더 나은 스택 추적을 얻는 데 도움이 될 수 있습니다.

자세한 내용은 DTrace Action Basics 를 참조하십시오.


답변