Diagnosticando o alto uso da CPU no Docker for Mac

20

Como diagnosticar a causa do Docker no MacOS, com.docker.hyperkitusando especificamente 100% da CPU?

uso da CPU do docker

Estatísticas do Docker

As estatísticas do Docker mostram que todos os contêineres em execução têm pouca CPU, memória, E / S líquida e E / S de bloco.

saída de estatísticas do docker

iosnoop

O iosnoop mostra que com.docker.hyperkitrealiza cerca de 50 gravações por segundo, totalizando 500 KB por segundo no arquivo Docker.qcow2. De acordo com o que é o Docker.qcow2? , Docker.qcow2é um arquivo esparso que é o armazenamento persistente para todos os contêineres do Docker.

No meu caso, o arquivo não é tão escasso. O tamanho físico corresponde ao tamanho lógico.

tamanho real do docker.qcow

dtrace (dtruss)

O dtruss sudo dtruss -p $DOCKER_PIDmostra um grande número de chamadas psynch_cvsignale psynch_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

Atualização: topno host do Docker

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

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

O uso da CPU no host incorporado do docker é de ~ 3%. O uso da CPU no meu MacBook foi de ~ 100%. Portanto, o host incorporado do docker não está causando o pico de uso da CPU.

parte superior do host do docker

Atualização: executando scripts dtrace dos rastreamentos de pilha mais comuns

Empilhe rastreamentos dos scripts dtrace na resposta abaixo: https://stackoverflow.com/a/58293035/30900 .

Esses rastreamentos de pilha do kernel parecem inócuos.

              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

Os rastreamentos de pilha mais comuns no espaço do usuário por 17 segundos implicam claramente o com.docker.hyperkit. Existem 1365 rastreamentos de pilha em 17 segundos, nos quais os com.docker.hyperkitthreads são criados com uma média de 80 threads por segundo.

              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

Assuntos relacionados

Github - docker / for-mac: com.docker.hyperkit 100% de uso da CPU está de volta # 3499 . Um comentário sugere adicionar o cache de volume descrito aqui: https://www.docker.com/blog/user-guided-caching-in-docker-for-mac/ . Eu tentei isso e obtive uma pequena redução de ~ 10% no uso da CPU.

Joe
fonte
Você está construindo imagens? Eu também focaria em contêineres que executam muitas E / S de blocos. Também importa se você ativou o Kubernetes.
BMitch 8/10/19
11
Eu coletei todas as métricas depois que o cluster foi criado e em execução por alguns minutos. Kubernetes está desativado. Porém, nenhuma das máquinas executa muitas E / S de blocos. Os contêineres não estão fazendo nada. Notei que o uso da CPU parece aproximadamente correlacionado com o número de contêineres.
8109 Joe
Quantos núcleos / cpu você possui na máquina?
BMitch 9/10/19
Além disso, você tentou reiniciar a janela de encaixe, não os contêineres, mas todo o mecanismo e o cliente da área de trabalho?
BMitch 9/10/19
Estou executando um 2018 MBP 2.8 GHz Core i7 com 4 núcleos. Tentei ajustar o número de núcleos da CPU para o mecanismo do Docker. Eu tentei 1, 3, 4 e 6 núcleos. A restrição ao docker reduziu o uso da CPU de 100% para 60%.
Joe

Respostas:

5

Eu tenho o mesmo problema. Minha% de CPU voltou ao normal depois que removi todos os meus volumes.

docker system prune --volumes

Também removi manualmente alguns volumes nomeados:

docker volume rm NameOfVolumeHere

Isso não resolve o problema geral de não poder usar volumes com o Docker para mac. No momento, estou apenas sendo cuidadoso com a quantidade de volumes que uso e fechando a área de trabalho do Docker quando não estiver em uso.

Chris Adams
fonte
3

Minha suspeita é que o problema esteja relacionado à IO. Com volumes MacOS, isso envolve osxfs, onde há algum ajuste de desempenho que você pode executar. Principalmente, se você pode aceitar menos verificações de consistência, pode definir o modo de volume para delegatedobter um desempenho mais rápido. Consulte os documentos para obter mais detalhes: https://docs.docker.com/docker-for-mac/osxfs-caching/ . No entanto, se sua imagem contiver um grande número de arquivos pequenos, o desempenho será prejudicado, especialmente se você também tiver muitas camadas de imagem.

Você também pode tentar o seguinte comando para depurar qualquer problema de processo na VM incorporada que a janela de encaixe usa:

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

(Para sair, use <ctrl>-c)


Para rastrear se é IO, você também pode tentar o seguinte:

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

Isso será executado dentro do contêiner alpino em execução no espaço de nomes pid da VM, mostrando qualquer E / S que ocorra em qualquer processo, independentemente de esse processo estar ou não dentro de um contêiner. As estatísticas são a cada 5 segundos por um minuto (12 vezes) e, em seguida, fornece uma tabela média por processo. Você pode <ctrl>-ddestruir o contêiner alpino.


A partir dos comentários e edições, essas estatísticas podem ser verificadas. Um MBP de 4 núcleos possui 8 threads; portanto, a utilização total da CPU deve ser de 800% se o MacOS estiver relatando o mesmo que outros sistemas baseados em Unix. Dentro da VM, há mais de 100% de carga mostrada no comando superior da média no último minuto (embora menos das médias 5 e 15), que é aproximadamente o que você vê no processo de hiperkit no host. O uso instantâneo é superior a 12% do topo, e não 3%, pois é necessário adicionar as porcentagens do sistema e do usuário. E os números de E / S mostrados no pidstat se alinham aproximadamente ao que você vê gravado na imagem qcow2.


Se o próprio mecanismo do docker estiver debulhando (por exemplo, reiniciando contêineres ou executando muitas verificações de integridade), você poderá depurá-lo observando a saída de:

docker events
BMitch
fonte
Alterei todas as montagens de volume para delegatedmas não houve melhora no desempenho. Executei o topcomando na VM incorporada, mas o uso da CPU ficou em torno de ~ 3%.
Joe
Atualizado pidstatpara acompanhar melhor os problemas de IO.
BMitch 9/10/19
pidstatmostra leituras para todos os PIDs são 0 kB / s. Para gravações: logwriteescreve 8,5kB / s em média e influxdgrava 0,61kB / s em média. O restante dos processos é 0. #
Joe Joe
1

Este é um pequeno script do dTrace que eu uso para descobrir onde o kernel está gastando seu tempo (é do Solaris e remonta aos primeiros dias do Solaris 10):

#!/usr/sbin/dtrace -s

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

Ele simplesmente mostra os rastreamentos da pilha do kernel e conta cada um que encontra na @hotagregação.

Execute-o como root:

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

Deixe-o funcionar por um período decente enquanto estiver com problemas na CPU e pressione CTRL-Cpara quebrar o script. Ele emitirá todos os rastreamentos de pilha do kernel que encontrou, o último mais comum. Se você precisar de mais (ou menos) quadros de pilha do padrão com

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

Isso mostrará um quadro de pilha com 15 chamadas profundas.

Os últimos rastreamentos de pilha serão onde seu kernel passa a maior parte do tempo. Isso pode ou não ser informativo.

Este script fará o mesmo para rastreamentos de pilha de espaço do usuário:

#!/usr/sbin/dtrace -s

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

Execute-o da mesma forma:

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

ustack() é um pouco mais lento - para emitir os nomes das funções reais, o dTrace precisa trabalhar muito mais para obtê-los dos espaços de endereço dos processos apropriados.

Desabilitar a Proteção de Integridade do Sistema pode ajudá-lo a obter melhores rastreamentos de pilha.

Consulte DTrace Action Basics para obter mais detalhes.

Andrew Henle
fonte
Obrigado, atualizei a pergunta com os resultados dos scripts. Os rastreios de pilha do espaço do usuário mostram com.docker.hyperkit cria muitos encadeamentos.
Joe