Diagnóstico de uso elevado de CPU en Docker para Mac

20

¿Cómo diagnostico la causa de Docker en MacOS, específicamente com.docker.hyperkitusando el 100% de la CPU?

uso de la CPU del acoplador

Estadísticas de Docker

Las estadísticas de Docker muestran que todos los contenedores en ejecución tienen poca CPU, memoria, IO neto y IO bloqueado.

salida de estadísticas del acoplador

iosnoop

iosnoop muestra que com.docker.hyperkitrealiza alrededor de 50 escrituras por segundo con un total de 500 KB por segundo en el archivo Docker.qcow2. De acuerdo con ¿Qué es Docker.qcow2? , Docker.qcow2es un archivo disperso que es el almacenamiento persistente para todos los contenedores Docker.

En mi caso, el archivo no es tan escaso. El tamaño físico coincide con el tamaño lógico.

docker.qcow tamaño real

dtrace (dtruss)

dtruss sudo dtruss -p $DOCKER_PIDmuestra una gran cantidad de psynch_cvsignaly psynch_cvwaitllamadas.

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

Actualización: topen el host Docker

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

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

El uso de CPU en el host integrado de Docker es de ~ 3%. El uso de la CPU en mi MacBook fue de ~ 100%. Por lo tanto, el host integrado docker no está causando el pico de uso de la CPU.

docker host top

Actualización: ejecutar scripts dtrace de los seguimientos de pila más comunes

Apile las trazas de los scripts de dtrace en la respuesta a continuación: https://stackoverflow.com/a/58293035/30900 .

Estos rastros de la pila del kernel parecen inocuos.

              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

Los rastros de pila más comunes en el espacio del usuario durante 17 segundos implican claramente com.docker.hyperkit. Hay 1365 seguimientos de pila en 17 segundos en los que se com.docker.hyperkitcrean hilos que promedian 80 hilos 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

Asuntos relacionados

Github - docker / for-mac: com.docker.hyperkit El uso del 100% de la CPU está de vuelta nuevamente # 3499 . Un comentario sugiere agregar el almacenamiento en caché de volumen descrito aquí: https://www.docker.com/blog/user-guided-caching-in-docker-for-mac/ . Intenté esto y obtuve una pequeña reducción del 10% en el uso de la CPU.

Joe
fuente
¿Estás construyendo imágenes? También me enfocaría en los contenedores que realizan una gran cantidad de bloque IO. También importa si ha habilitado Kubernetes.
BMitch
1
Recopilé todas las métricas después de que el clúster se creó y se ejecutó durante unos minutos. Kubernetes está deshabilitado. Sin embargo, ninguna de las máquinas realiza una gran cantidad de bloque IO. Los contenedores no están haciendo nada. Me di cuenta de que el uso de la CPU parece estar correlacionado con la cantidad de contenedores.
Joe
¿Cuántos núcleos / CPU tiene en la máquina?
BMitch
Además, ¿ha intentado reiniciar Docker, no los contenedores, sino todo el motor y el cliente de escritorio?
BMitch
Estoy ejecutando un 2018 MBP 2.8 GHz Core i7 con 4 núcleos. Intenté ajustar la cantidad de núcleos de CPU para el motor Docker. Intenté 1, 3, 4 y 6 núcleos. La restricción a la ventana acoplable redujo el uso de CPU del 100% al 60%.
Joe

Respuestas:

5

Tengo el mismo problema. Mi CPU% volvió a la normalidad después de que eliminé todos mis volúmenes.

docker system prune --volumes

También eliminé manualmente algunos volúmenes con nombre:

docker volume rm NameOfVolumeHere

Eso no resuelve el problema general de no poder usar volúmenes con Docker para mac. En este momento solo estoy teniendo cuidado con la cantidad de volúmenes que uso y cerrando el escritorio de Docker cuando no estoy en uso.

Chris Adams
fuente
3

Mi sospecha es que el problema está relacionado con IO. Con los volúmenes de MacOS, esto implica osxfs donde hay algunos ajustes de rendimiento que puede realizar. Principalmente, si puede aceptar menos comprobaciones de consistencia, puede configurar el modo de volumen delegatedpara un rendimiento más rápido. Consulte los documentos para obtener más detalles: https://docs.docker.com/docker-for-mac/osxfs-caching/ . Sin embargo, si su imagen contiene una gran cantidad de archivos pequeños, el rendimiento se verá afectado, especialmente si también tiene muchas capas de imágenes.

También puede probar el siguiente comando para depurar cualquier problema de proceso dentro de la VM incorporada que utiliza la ventana acoplable:

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

(Para salir, use <ctrl>-c)


Para rastrear si es IO, también puede intentar lo siguiente:

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

Eso se ejecutará dentro del contenedor alpino que se ejecuta en el espacio de nombres pid de VM, mostrando cualquier E / S que ocurra desde cualquier proceso, ya sea que ese proceso esté o no dentro de un contenedor. Las estadísticas son cada 5 segundos durante un minuto (12 veces) y luego le dará una tabla promedio por proceso. Entonces puedes <ctrl>-ddestruir el contenedor alpino.


De los comentarios y ediciones, estas estadísticas pueden ver. Un MBP de 4 núcleos tiene 8 subprocesos, por lo que la utilización total de la CPU debería ser del 800% si MacOS informa lo mismo que otros sistemas basados ​​en Unix. Dentro de la VM hay más del 100% de carga que se muestra en el comando superior para el promedio en el último minuto (aunque menos de los promedios 5 y 15), que es aproximadamente lo que se ve para el proceso de hiperkit en el host. El uso instantáneo es superior al 12% desde la parte superior, no al 3%, ya que debe agregar el sistema y los porcentajes de usuario. Y los números IO que se muestran en pidstat se alinean aproximadamente con lo que ves escrito en la imagen qcow2.


Si el motor de la ventana acoplable se está agitando (por ejemplo, reiniciando contenedores o ejecutando muchas comprobaciones de estado), puede depurarlo observando la salida de:

docker events
BMitch
fuente
Cambié todos los montajes de volumen delegatedpero no hubo mejora en el rendimiento. Ejecuté el topcomando en la VM incorporada, pero el uso de la CPU rondaba el ~ 3%.
Joe
Actualizado con pidstatpara rastrear mejor los problemas de E / S.
BMitch
pidstatmuestra lecturas para todos los PID son 0 kB / s. Para escrituras: logwriteescribe 8.5kB / s en promedio y influxdescribe 0.61kB / s en promedio. El resto de los procesos son 0.
Joe
1

Este es un pequeño script de dTrace que uso para encontrar dónde el kernel pasa su tiempo (es de Solaris y se remonta a los primeros días de Solaris 10):

#!/usr/sbin/dtrace -s

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

Simplemente muestra los rastros de la pila del núcleo y cuenta cada uno que encuentra en la @hotagregación.

Ejecútelo como root:

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

Deje que se ejecute durante una cantidad de tiempo decente mientras tiene problemas con la CPU, luego presione CTRL-Cpara romper el script. Emitirá todos los rastros de la pila del núcleo que encontró, el último más común. Si necesita más (o menos) marcos de pila por defecto con

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

Eso mostrará un marco de pila de 15 llamadas de profundidad.

Las últimas trazas de la pila serán donde su núcleo pasa la mayor parte de su tiempo. Eso puede o no ser informativo.

Este script hará lo mismo para los seguimientos de pila de espacio de usuario:

#!/usr/sbin/dtrace -s

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

Ejecútelo de manera similar:

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

ustack() es un poco más lento: para emitir los nombres de funciones reales, dTrace tiene que hacer mucho más trabajo para obtenerlos de los espacios de direcciones de los procesos apropiados.

Deshabilitar la Protección de integridad del sistema puede ayudarlo a obtener mejores rastros de pila.

Consulte DTrace Action Basics para obtener más detalles.

Andrew Henle
fuente
Gracias, actualicé la pregunta con los resultados de los scripts. Los seguimientos de pila de espacio de usuario muestran que com.docker.hyperkit crea muchos hilos.
Joe