Диагностика высокой загрузки процессора в Docker для Mac

20

Как мне диагностировать причину Docker на MacOS, особенно com.docker.hyperkitиспользуя 100% процессорного времени?

загрузка процессора докером

Статистика Docker

Статистика Docker показывает, что все запущенные контейнеры имеют низкий процессор, память, чистый ввод-вывод и блочный ввод-вывод.

вывод статистики докера

iosnoop

iosnoop показывает, что com.docker.hyperkitв файл выполняется около 50 операций записи в секунду, что составляет 500 КБ в секунду Docker.qcow2. По словам Что такое Docker.qcow2? , Docker.qcow2это разреженный файл, который является постоянным хранилищем для всех контейнеров Docker.

В моем случае файл не так уж редок. Физический размер соответствует логическому размеру.

docker.qcow реальный размер

Dtrace (Dtruss)

dtruss sudo dtruss -p $DOCKER_PIDпоказывает большое количество psynch_cvsignalи 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

Обновление: topна хосте Docker

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

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

Загрузка ЦП на встроенном хосте докера составляет ~ 3%. Загрузка процессора на моем MacBook составила ~ 100%. Таким образом, встроенный хост докера не вызывает скачок загрузки процессора.

вершина хоста докера

Обновление: запуск сценариев dtrace наиболее распространенных трассировок стека

Составьте трассировку из сценариев dtrace в ответе ниже: https://stackoverflow.com/a/58293035/30900 .

Эти следы стека ядра выглядят безобидными.

              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. Там 1365 стековых трасс за 17 секунд, в которых 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% использование процессора снова вернулось # 3499 . Один комментарий предлагает добавить объемное кэширование, описанное здесь: https://www.docker.com/blog/user-guided-caching-in-docker-for-mac/ . Я попробовал это и получил небольшое ~ 10% снижение загрузки процессора.

Джо
источник
Вы строите изображения? Я бы также сосредоточился на контейнерах, выполняющих много блоков ввода-вывода. Также имеет значение, включили ли вы Kubernetes.
BMitch
1
Я собрал все метрики после того, как кластер был собран и запущен в течение нескольких минут. Кубернетес отключен. Ни одна из машин не выполняет много блоков ввода-вывода, хотя. Контейнеры ничего не делают. Я заметил, что загрузка ЦП примерно коррелирует с количеством контейнеров.
Джо
Сколько ядер / процессоров у вас на машине?
BMitch
Кроме того, вы пробовали перезапустить докер, не контейнеры, а весь движок и клиент рабочего стола?
BMitch
Я использую процессор Core i7 с тактовой частотой 2,8 ГГц с тактовой частотой 2,8 ГГц и 2018 МБ. Я попытался настроить количество ядер процессора для движка Docker. Я пробовал 1, 3, 4 и 6 ядер. Ограничение для докера уменьшило использование процессора со 100% до 60%.
Джо

Ответы:

5

У меня такая же проблема. Мой CPU% вернулся к нормальному состоянию после того, как я удалил все свои тома.

docker system prune --volumes

Я также вручную удалил некоторые именованные тома:

docker volume rm NameOfVolumeHere

Это не решает общую проблему невозможности использования томов с Docker для Mac. Сейчас я просто осторожен с количеством используемых томов и закрываю рабочий стол Docker, когда он не используется.

Крис Адамс
источник
3

Я подозреваю, что проблема связана с IO. В томах MacOS это включает osxfs, где вы можете выполнить некоторые настройки производительности. Главным образом, если вы можете принять меньше проверок согласованности, вы можете установить режим громкости delegatedдля повышения производительности. См. Документы для более подробной информации: https://docs.docker.com/docker-for-mac/osxfs-caching/ . Однако, если ваше изображение содержит большое количество небольших файлов, производительность будет снижаться, особенно если у вас также есть много слоев изображения.

Вы также можете попробовать следующую команду для отладки любых проблем процесса во встроенной виртуальной машине, которые использует Docker:

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, показывая любой ввод-вывод, происходящий из любого процесса, независимо от того, находится ли этот процесс внутри контейнера. Статистика каждые 5 секунд в течение одной минуты (12 раз), а затем она даст вам среднюю таблицу за процесс. Затем вы можете <ctrl>-dуничтожить альпийский контейнер.


Из комментариев и правок эти статистические данные могут проверить. 4-ядерный MBP имеет 8 потоков, поэтому полная загрузка ЦП должна составлять 800%, если MacOS сообщает то же самое, что и другие системы на основе Unix. Внутри виртуальной машины более 100% нагрузки показано в верхней команде для среднего значения за последнюю минуту (хотя и меньше, чем 5 и 15 средних значений), что примерно соответствует показателю процесса гиперкита на хосте. Мгновенное использование превышает 12% сверху, а не 3%, так как вам нужно добавить системные и пользовательские проценты. И числа IO, показанные в pidstat, примерно совпадают с тем, что вы видите записанным на образе qcow2.


Если механизм докера сам перебивает (например, перезапускает контейнеры или запускает много проверок работоспособности), вы можете отладить это, просмотрев вывод:

docker events
BMitch
источник
Я изменил все объемные крепления, delegatedно улучшения производительности не было. Я запустил topкоманду на встроенной виртуальной машине, но загрузка процессора колебалась в пределах ~ 3%.
Джо
Обновлен с, pidstatчтобы лучше отслеживать проблемы ввода-вывода.
BMitch
pidstatПоказывает чтения для всех PID 0 кБ / с. Для записи: logwriteзаписывает в среднем 8,5 КБ / с и influxdпишет в среднем 0,61 КБ / с. Остальные процессы 0.
Джо
1

Это небольшой скрипт dTrace, который я использую, чтобы узнать, где ядро ​​тратит свое время (он из Solaris и восходит к ранним версиям Solaris 10):

#!/usr/sbin/dtrace -s

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

Он просто отбирает трассировки стека ядра и подсчитывает каждую из встреченных в @hotагрегации.

Запустите его как root:

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

Дайте ему поработать приличное количество времени, пока у вас возникают проблемы с процессором, затем нажмите, 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 для некоторых подробностей.

Эндрю Хенле
источник
Спасибо, я обновил вопрос с результатами скриптов. Трассировки стека в пользовательском пространстве показывают, что com.docker.hyperkit создает много потоков.
Джо