Существует проблема в распределении ресурсов в контейнерах 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).