Предотвращение перезагрузки процессора контейнера Docker? - PullRequest
0 голосов
/ 31 октября 2018

Это сложный вопрос, и его немного сложно объяснить, но я постараюсь показать, есть ли у кого-нибудь подобная проблема + исправление.

Быстрый фон:
Запуск большого Java Spring App на Tomcat в контейнере Docker. Другие контейнеры просты: 1 для JMS Queue и другой для Mysql. Я работаю в Windows и отдам Docker столько процессоров, сколько у меня есть (и памяти тоже). Я установил JAVA_OPTS для Catalina, чтобы максимально использовать память, а также ограничения памяти в моем docker-compose, но проблема, похоже, связана с процессором.

Когда приложение работает на холостом ходу, оно обычно занимает около 103% ЦП (8 ядер, макс. 800%). Есть процесс, который мы используем, который (используя Thread Pool) запускает некоторых рабочих для запуска и запуска некоторого кода. На моем локальном хосте (между ними нет докера) он работает очень быстро и вылетает, выплевывая логи в хорошем клипе.

Проблема: Когда я запускаю в Docker, наблюдая за docker stats -a, я вижу, как процессор начинает увеличиваться, когда начинается этот процесс. Между тем в журналах все пролетает, как и ожидалось, в то время как процессор растет и растет. Кажется, он приближается к 700%, а потом умирает, но это не так. Когда он достигает этого порога, я вижу резкое падение ЦП до <5%, где он остается некоторое время. В это время журналы перестают печататься, поэтому я предполагаю, что ничего не происходит. В конце концов он откатится назад и вернется на ~ 120% и продолжит свой процесс, как будто ничего не произошло, иногда дыша до ~ 400%. </p>

Что я пытаюсь

Я поиграл с настройками памяти, но безуспешно, но это больше похоже на проблему с процессором. Я знаю, что Java в Docker немного утомительна, но я предоставил ему все возможности на своем мощном устройстве разработки, где локально этот процесс выполняется без проблем. Я нахожу странным, что пики процессора умирают, но сам контейнер не умирает и не сбрасывается. Кто-нибудь видел подобную проблему или знает какие-либо способы дальнейшей атаки этой проблемы с процессором с помощью Docker?

Спасибо.

1 Ответ

0 голосов
/ 24 июня 2019

Существует проблема в распределении ресурсов в контейнерах JVM, которая возникает при обращении к общим системным матрицам вместо матриц контейнеров. В JAVA 7 и 8 эргономика JVM применяет матрицы (экземпляры) системы, такие как количество ядер и память, вместо ресурсов, выделяемых докером (ядра и память). В результате этого JVM инициализировала ряд параметров на основе количества ядер и памяти, как показано ниже.

Следы памяти JVM

-perm / Метапространство

-JIT Байт-код

-Размер кучи (эргономика JVM memory памяти экземпляра)

Процессор

-Нет. Потоки JIT-компилятора

-Нет. Нитки для сбора мусора

-Нет. Поток в общем пуле объединения вил

Таким образом, контейнеры, как правило, перестают отвечать из-за высокой загрузки ЦП или завершают работу контейнера при уничтожении OOM. Причина этого заключается в том, что контейнер CGGroups и пространства имен игнорируются JVM для ограничения циклов памяти и ЦП. Поэтому JVM стремится получать больше ресурсов экземпляра, а не ограничивать отдельное выделение ресурсов, выделенных Docker.E

Пример * * тысяча двадцать-одна

Предположим, что два контейнера работают на 4-ядерном экземпляре с 8 ГБ памяти. Когда дело доходит до точки инициализации докера, предположим, что докер имеет 1 ГБ памяти и 2048 циклов ЦП в качестве жесткого ограничения. Здесь каждый контейнер видит 4 ядра, и эти JVM распределяют память, JIT-компиляторы и потоки GC отдельно в соответствии со своей статистикой. Однако JVM увидит общее количество ядер в этом экземпляре (4) и использует это значение для инициализации количества потоков по умолчанию, которое мы видели ранее. Соответственно, матрицы JVM двух контейнеров будут такими, как указано ниже.

-4 * 2 темы компилятора Jit

-4 * 2 темы сборки мусора

-2 ГБ Размер кучи * 2 (full полной памяти экземпляра вместо выделенной памяти докеру)

С точки зрения памяти

Согласно приведенному выше примеру, JVM будет постепенно увеличивать использование кучи, поскольку JVM видит максимальный размер кучи 2 ГБ, что составляет четверть памяти экземпляра (8 ГБ). Как только использование памяти контейнера достигнет жесткого предела в 1 ГБ, контейнер будет прерван OOM kill.

В пересчете на CPU

Согласно приведенному выше примеру, одна JVM инициализирована с 4-мя потоками сборки мусора и 4-мя JIT-компилятором. Однако докер выделяет только 2048 тактов процессора. Следовательно, это приводит к высокой загрузке ЦП, большему количеству переключений контекста и не отвечает на запросы контейнера, и, наконец, завершает работу контейнера из-за высокой загрузки ЦП.

Решение По сути, есть два процесса, а именно, CGGroups и пространства имен, которые обрабатывают такую ​​ситуацию на уровне ОС. Однако JAVA 7 и 8 не принимают CGgroup и пространства имен, но выпуски после jdk_1.8.131 могут включать ограничение CGroup по параметру JVM (-XX: + UseCGroupMemoryLimitForHeap, -XX: + UnlockExperimentalVMOptions). Тем не менее, он предоставляет только решения проблем с памятью, но не заботится о проблемах с установленным процессором.

В OpenJDK 9 JVM автоматически обнаружит наборы процессоров. Особенно в оркестровке, он также может вручную перезаписывать параметры по умолчанию для числа потоков набора ЦП согласно количеству циклов ЦП в контейнере, используя флаги JVM (XX: ParallelGCThreads, XX: ConcGCThreads).

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...