Diagnostic de l'utilisation élevée du processeur sur Docker pour Mac

20

Comment diagnostiquer la cause de Docker sur MacOS, en com.docker.hyperkitutilisant spécifiquement 100% du CPU?

utilisation du processeur Docker

Statistiques Docker

Les statistiques de Docker montrent que tous les conteneurs en cours d'exécution ont un processeur, une mémoire, des E / S nets et des E / S de bloc faibles.

sortie des statistiques de docker

iosnoop

iosnoop montre qu'il com.docker.hyperkiteffectue environ 50 écritures par seconde totalisant 500 Ko par seconde dans le fichier Docker.qcow2. Selon Qu'est-ce que Docker.qcow2? , Docker.qcow2est un fichier clairsemé qui est le stockage persistant de tous les conteneurs Docker.

Dans mon cas, le fichier n'est pas si clairsemé. La taille physique correspond à la taille logique.

docker.qcow taille réelle

dtrace (dtruss)

dtruss sudo dtruss -p $DOCKER_PIDaffiche un grand nombre d' appels psynch_cvsignalet 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

Mise à jour: topsur l'hôte Docker

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

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

L'utilisation du processeur sur l'hôte intégré Docker est de ~ 3%. L'utilisation du processeur sur mon MacBook était d'environ 100%. Ainsi, l'hôte intégré de docker ne provoque pas de pic d'utilisation du processeur.

haut hôte docker

Mise à jour: exécution de scripts dtrace des traces de pile les plus courantes

Empilez les traces des scripts dtrace dans la réponse ci-dessous: https://stackoverflow.com/a/58293035/30900 .

Ces traces de pile de noyau semblent inoffensives.

              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

Les traces de pile les plus courantes dans l'espace utilisateur sur 17 secondes impliquent clairement com.docker.hyperkit. Il y a 1365 traces de pile en 17 secondes dans lesquelles ont com.docker.hyperkitcréé des threads qui font en moyenne 80 threads par seconde.

              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

Problèmes liés

Github - Docker / pour Mac: com.docker.hyperkit 100% CPU est de retour # 3499 . Un commentaire suggère d'ajouter la mise en cache de volume décrite ici: https://www.docker.com/blog/user-guided-caching-in-docker-for-mac/ . J'ai essayé cela et j'ai obtenu une petite réduction de ~ 10% de l'utilisation du processeur.

Joe
la source
Construisez-vous des images? Je me concentrerais également sur les conteneurs effectuant beaucoup d'E / S de blocs. Il importe également que vous ayez activé Kubernetes.
BMitch
1
J'ai collecté toutes les métriques après la création et le fonctionnement du cluster pendant quelques minutes. Kubernetes est désactivé. Cependant, aucune des machines n'effectue beaucoup d'E / S de bloc. Les conteneurs ne font rien. J'ai remarqué que l'utilisation du processeur semble à peu près corrélée au nombre de conteneurs.
Joe
Combien de cœurs / processeurs avez-vous sur la machine?
BMitch
De plus, avez-vous essayé de redémarrer Docker, pas les conteneurs, mais l'ensemble du moteur et du client de bureau?
BMitch
J'utilise un Core i7 MBP 2,8 GHz 2018 avec 4 cœurs. J'ai essayé de modifier le nombre de cœurs de processeur pour le moteur Docker. J'ai essayé 1, 3, 4 et 6 cœurs. Restreindre à Docker a réduit l'utilisation du processeur de 100% à 60%.
Joe

Réponses:

5

J'ai le même problème. Mon CPU% est revenu à la normale après avoir supprimé tous mes volumes.

docker system prune --volumes

J'ai également supprimé manuellement certains volumes nommés:

docker volume rm NameOfVolumeHere

Cela ne résout pas le problème global de ne pas pouvoir utiliser les volumes avec Docker pour mac. Pour l'instant, je fais juste attention à la quantité de volumes que j'utilise et je ferme le bureau Docker lorsqu'il n'est pas utilisé.

Chris Adams
la source
3

Je soupçonne que le problème est lié aux E / S. Avec les volumes MacOS, cela implique osxfs où vous pouvez effectuer certains réglages des performances. Surtout, si vous pouvez accepter moins de contrôles de cohérence, vous pouvez définir le mode de volume sur delegatedpour des performances plus rapides. Voir la documentation pour plus de détails: https://docs.docker.com/docker-for-mac/osxfs-caching/ . Cependant, si votre image contient un grand nombre de petits fichiers, les performances en souffriront, surtout si vous avez également beaucoup de couches d'image.

Vous pouvez également essayer la commande suivante pour déboguer tout problème de processus dans la machine virtuelle intégrée que docker utilise:

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

(Pour quitter, utilisez <ctrl>-c)


Pour rechercher s'il s'agit d'E / S, vous pouvez également essayer ce qui suit:

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

Cela s'exécutera à l'intérieur du conteneur alpin exécuté dans l'espace de noms VM pid, montrant tout IO se produisant à partir de n'importe quel processus, que ce processus soit ou non à l'intérieur d'un conteneur. Les statistiques sont toutes les 5 secondes pendant une minute (12 fois), puis elles vous donneront une table moyenne par processus. Vous pouvez alors <ctrl>-ddétruire le conteneur alpin.


D'après les commentaires et les modifications, ces statistiques peuvent être vérifiées. Un MBP à 4 cœurs a 8 threads, donc l'utilisation complète du processeur devrait être de 800% si MacOS rapporte les mêmes que les autres systèmes basés sur Unix. À l'intérieur de la machine virtuelle, il y a plus de 100% de charge indiquée dans la commande supérieure pour la moyenne au cours de la dernière minute (bien que moins que les moyennes de 5 et 15), ce qui est à peu près ce que vous voyez pour le processus d'hyperkit sur l'hôte. L'utilisation instantanée est supérieure à 12% par rapport au sommet, et non à 3%, car vous devez ajouter les pourcentages système et utilisateur. Et les nombres d'E / S affichés dans pidstat s'alignent à peu près avec ce que vous voyez écrit sur l'image qcow2.


Si le moteur docker lui-même est en train de se déborder (par exemple, redémarrer des conteneurs ou exécuter de nombreux contrôles de santé), vous pouvez le déboguer en regardant la sortie de:

docker events
BMitch
la source
J'ai changé tous les supports de volume en delegatedmais il n'y a pas eu d'amélioration des performances. J'ai exécuté la topcommande sur la machine virtuelle intégrée, mais l'utilisation du processeur a oscillé autour de ~ 3%.
Joe
Mise à jour avec pidstatpour mieux suivre les problèmes d'E / S.
BMitch
pidstatindique que les lectures pour tous les PID sont de 0 ko / s. Pour les écritures: logwriteécrit 8,5 Ko / s en moyenne et influxdécrit 0,61 Ko / s en moyenne. Le reste des processus est 0.
Joe
1

Il s'agit d'un petit script dTrace que j'utilise pour trouver où le noyau passe son temps (il vient de Solaris et remonte aux premiers jours de Solaris 10):

#!/usr/sbin/dtrace -s

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

Il échantillonne simplement les traces de pile de noyau et compte chacune qu'il rencontre dans l' @hotagrégation.

Exécutez-le en tant que root:

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

Laissez-le fonctionner pendant une période décente pendant que vous rencontrez des problèmes de processeur, puis appuyez sur CTRL-Cpour casser le script. Il émettra toutes les traces de pile du noyau rencontrées, la dernière la plus courante. Si vous avez besoin de plus (ou moins) de cadres de pile par défaut avec

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

Cela montrera une trame de pile de 15 appels en profondeur.

Les dernières traces de pile seront celles où votre noyau passe la plupart de son temps. Cela peut ou non être informatif.

Ce script fera de même pour les traces de pile de l'espace utilisateur:

#!/usr/sbin/dtrace -s

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

Exécutez-le de la même manière:

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

ustack() est un peu plus lent - pour émettre les noms de fonction réels, dTrace doit faire beaucoup plus de travail pour les extraire des espaces d'adressage des processus appropriés.

La désactivation de la protection de l'intégrité du système peut vous aider à obtenir de meilleures traces de pile.

Voir Bases de l'action DTrace pour plus de détails.

Andrew Henle
la source
Merci, j'ai mis à jour la question avec les résultats des scripts. Les traces de pile de l'espace utilisateur montrent que com.docker.hyperkit crée un grand nombre de threads.
Joe