Diagnose einer hohen CPU-Auslastung unter Docker für Mac

20

Wie diagnostiziere ich die Ursache von Docker unter MacOS, insbesondere unter com.docker.hyperkitVerwendung von 100% der CPU?

Docker-CPU-Auslastung

Docker-Statistiken

Docker-Statistiken zeigen, dass alle laufenden Container wenig CPU, Speicher, Netto-E / A und Block-E / A haben.

Docker-Statistik-Ausgabe

iosnoop

iosnoop zeigt, dass com.docker.hyperkitungefähr 50 Schreibvorgänge pro Sekunde ausgeführt werden, insgesamt 500 KB pro Sekunde in die Datei Docker.qcow2. Laut Was ist Docker.qcow2? , Docker.qcow2Ist eine Datei mit geringer Dichte , die die persistenten Speicher für alle Docker - Container ist.

In meinem Fall ist die Datei nicht so dünn. Die physische Größe entspricht der logischen Größe.

docker.qcow tatsächliche Größe

dtrace (dtruss)

dtruss sudo dtruss -p $DOCKER_PIDzeigt eine große Anzahl von psynch_cvsignalund psynch_cvwaitAnrufe.

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

Update: topauf Docker-Host

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

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

Die CPU-Auslastung auf dem eingebetteten Docker-Host beträgt ~ 3%. Die CPU-Auslastung meines MacBook betrug ~ 100%. Der eingebettete Docker-Host verursacht also keinen Anstieg der CPU-Auslastung.

Docker Host Top

Update: Ausführen von dtrace-Skripten der gängigsten Stack-Traces

Stapeln Sie Traces aus den dtrace-Skripten in der folgenden Antwort: https://stackoverflow.com/a/58293035/30900 .

Diese Kernel-Stack-Traces sehen harmlos aus.

              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

Die häufigsten Stapelspuren im Benutzerbereich über 17 Sekunden implizieren eindeutig com.docker.hyperkit. Es gibt 1365 Stapelspuren in 17 Sekunden, in denen com.docker.hyperkitThreads erstellt wurden, was einem Durchschnitt von 80 Threads pro Sekunde entspricht.

              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

Verwandte Themen

Github - docker / for-mac: com.docker.hyperkit 100% CPU-Auslastung ist wieder da # 3499 . Ein Kommentar schlägt vor, das hier beschriebene Volume-Caching hinzuzufügen: https://www.docker.com/blog/user-guided-caching-in-docker-for-mac/ . Ich habe dies versucht und eine kleine Reduzierung der CPU-Auslastung um ~ 10% erzielt.

Joe
quelle
Bauen Sie Bilder? Ich würde mich auch auf Container konzentrieren, die viel Block-E / A ausführen. Es ist auch wichtig, ob Sie Kubernetes aktiviert haben.
BMitch
1
Ich habe alle Metriken gesammelt, nachdem der Cluster erstellt und einige Minuten lang ausgeführt wurde. Kubernetes ist deaktiviert. Keine der Maschinen führt jedoch viel Block-E / A aus. Die Container machen nichts. Ich habe festgestellt, dass die CPU-Auslastung in etwa mit der Anzahl der Container korreliert.
Joe
Wie viele Kerne / CPUs haben Sie auf der Maschine?
BMitch
Haben Sie auch versucht, Docker neu zu starten, nicht die Container, sondern die gesamte Engine und den Desktop-Client?
BMitch
Ich verwende einen 2018 MBP 2,8 GHz Core i7 mit 4 Kernen. Ich habe versucht, die Anzahl der CPU-Kerne für die Docker-Engine zu optimieren. Ich habe 1, 3, 4 und 6 Kerne ausprobiert. Durch die Beschränkung auf Docker wurde die CPU-Auslastung von 100% auf 60% reduziert.
Joe

Antworten:

5

Ich habe das gleiche Problem. Meine CPU% wurde wieder normal, nachdem ich alle meine Volumes entfernt hatte.

docker system prune --volumes

Ich habe auch einige benannte Volumes manuell entfernt:

docker volume rm NameOfVolumeHere

Damit ist das allgemeine Problem nicht gelöst, dass mit Docker für Mac keine Volumes verwendet werden können. Im Moment bin ich nur vorsichtig mit der Menge der Volumes, die ich verwende, und schließe den Docker-Desktop, wenn er nicht verwendet wird.

Chris Adams
quelle
3

Mein Verdacht ist, dass das Problem mit IO zusammenhängt. Bei MacOS-Volumes handelt es sich um osxfs, bei denen eine Leistungsoptimierung durchgeführt werden kann. Wenn Sie weniger Konsistenzprüfungen akzeptieren können, können Sie den Lautstärkemodus hauptsächlich auf delegatedeine schnellere Leistung einstellen . Weitere Informationen finden Sie in den Dokumenten: https://docs.docker.com/docker-for-mac/osxfs-caching/ . Wenn Ihr Bild jedoch eine große Anzahl kleiner Dateien enthält, leidet die Leistung, insbesondere wenn Sie auch viele Bildebenen haben.

Sie können auch den folgenden Befehl verwenden, um Prozessprobleme in der vom Docker verwendeten eingebetteten VM zu debuggen:

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

(Zum Beenden verwenden Sie <ctrl>-c)


Um festzustellen, ob es sich um E / A handelt, können Sie auch Folgendes versuchen:

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

Dies wird im alpinen Container ausgeführt, der im VM-PID-Namespace ausgeführt wird, und zeigt alle E / A-Vorgänge an, die von einem Prozess ausgeführt werden, unabhängig davon, ob sich dieser Prozess in einem Container befindet oder nicht. Die Statistiken sind alle 5 Sekunden für eine Minute (12 Mal) und geben Ihnen dann eine durchschnittliche Tabelle pro Prozess. Sie können dann<ctrl>-d den Alpencontainer zerstören.


Aus den Kommentaren und Änderungen können diese Statistiken ausgecheckt werden. Ein 4-Kern-MBP hat 8 Threads, daher sollte die volle CPU-Auslastung 800% betragen, wenn MacOS dieselben Berichte wie andere Unix-basierte Systeme meldet. Innerhalb der VM wird im oberen Befehl für den Durchschnitt der letzten Minute eine Auslastung von über 100% angezeigt (allerdings weniger als bei den Durchschnittswerten von 5 und 15), was ungefähr dem Hyperkit-Prozess auf dem Host entspricht. Die sofortige Nutzung beträgt mehr als 12% von oben, nicht 3%, da Sie die System- und Benutzerprozentsätze hinzufügen müssen. Und die in pidstat angezeigten E / A-Nummern stimmen ungefähr mit denen überein, die auf dem qcow2-Image geschrieben sind.


Wenn die Docker-Engine selbst überlastet ist (z. B. Container neu starten oder viele Integritätsprüfungen ausführen), können Sie dies debuggen, indem Sie die Ausgabe von:

docker events
BMitch
quelle
Ich habe alle Volumenhalterungen auf geändert, delegatedaber es gab keine Leistungsverbesserung. Ich habe den topBefehl auf der eingebetteten VM ausgeführt, aber die CPU-Auslastung lag bei ~ 3%.
Joe
Aktualisiert mit pidstat, um E / A-Probleme besser verfolgen zu können.
BMitch
pidstatzeigt, dass die Lesevorgänge für alle PIDs 0 kB / s betragen. Für Schreibvorgänge: logwriteSchreibt durchschnittlich influxd8,5 kB / s und schreibt durchschnittlich 0,61 kB / s. Der Rest der Prozesse sind 0.
Joe
1

Dies ist ein kleines dTrace-Skript, mit dem ich herausfinde, wo der Kernel seine Zeit verbringt (es stammt aus Solaris und stammt aus den frühen Tagen von Solaris 10):

#!/usr/sbin/dtrace -s

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

Es werden einfach Kernel-Stack-Traces abgetastet und jede einzelne, auf die es in der @hotAggregation stößt, gezählt .

Führen Sie es als root aus:

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

Lassen Sie es für eine angemessene Zeit laufen, während Sie CPU-Probleme haben, und drücken Sie dann CTRL-C, um das Skript zu brechen. Es werden alle Kernel-Stack-Traces ausgegeben, auf die es gestoßen ist, die häufigste letzte. Wenn Sie mehr (oder weniger) Stapelrahmen von der Standardeinstellung mit benötigen

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

Das zeigt einen Stapelrahmen, der 15 Aufrufe tief ist.

In den letzten Stapelspuren verbringt Ihr Kernel die meiste Zeit. Das kann informativ sein oder auch nicht.

Dieses Skript macht dasselbe für User-Space-Stack-Traces:

#!/usr/sbin/dtrace -s

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

Führen Sie es ähnlich aus:

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

ustack() ist etwas langsamer - um die tatsächlichen Funktionsnamen auszugeben, muss dTrace viel mehr Arbeit leisten, um sie aus den Adressräumen der entsprechenden Prozesse zu erhalten.

Deaktivieren des Systemintegritätsschutzes können Sie möglicherweise bessere Stapelspuren erhalten.

Weitere Informationen finden Sie unter DTrace-Aktionsgrundlagen .

Andrew Henle
quelle
Danke, ich habe die Frage mit den Ergebnissen der Skripte aktualisiert. Die User-Space-Stack-Traces zeigen, dass com.docker.hyperkit viele Threads erstellt.
Joe