Является ли -XX: MaxRAMFraction = 1 безопасным для производства в изолированной среде?

Java 8/9 предоставила поддержку для -XX:+UseCGroupMemoryLimitForHeap-XX:+UnlockExperimentalVMOptions). Это устанавливает -XX:MaxRAM для ограничения памяти группы. По умолчанию JVM выделяет примерно 25% максимальной ОЗУ, потому что -XX:MaxRAMFraction умолчанию -XX:MaxRAMFraction 4.

Пример:

MaxRAM = 1g
MaxRAMFraction = 4
JVM is allowed to allocate: MaxRAM / MaxRAMFraction = 1g / 4 = 256m

Использование только 25% квоты кажется пустой для развертывания, которое (как правило) состоит из одного процесса JVM. Итак, теперь люди устанавливают -XX:MaxRAMFraction=1, поэтому JVM теоретически разрешено использовать 100% MaxRAM.

Для примера 1g это часто приводит к размерам кучи около 900 м. Это кажется немного большим - нет свободного места для JVM или других вещей, таких как удаленные оболочки или задачи вне процесса.

-XX:+UnlockExperimentalVMOptions -XX:+UseCGroupMemoryLimitForHeap -XX:MaxRAMFraction=1 так же эта конфигурация (-XX:+UnlockExperimentalVMOptions -XX:+UseCGroupMemoryLimitForHeap -XX:MaxRAMFraction=1) считается безопасным для prod или даже лучшей практики? Или мне еще нужно выбрать -Xmx, -Xms, -Xss и так далее?

Ответ 1

Мы провели простое тестирование, которое показало, что установка -XX:MaxRAM=$QUOTA и -XX:MaxRAMFraction=1 приводит к гибели контейнеров под нагрузкой. JVM выделяет более 900 миллионов кучи, что слишком много. -XX:MaxRAMFraction=2 кажется безопасным (ish).

Имейте в виду, что вы можете оставить запас для других процессов, таких как получение отладочной оболочки (docker exec) или диагностика в контейнере.


Изменение: мы написали то, что мы узнали подробно в статье. Денежные кавычки:

TL'DR: управление памятью Java и ее настройка все еще сложны. Хотя JVM может считывать ограничения памяти cgroup и соответствующим образом адаптировать использование памяти, начиная с Java 9/8u131, это не золотая пуля. Вам нужно знать, что делает -XX:+UseCGroupMemoryLimitForHeap, и вам нужно точно настроить некоторые параметры для каждого развертывания. В противном случае вы рискуете потратить ресурсы и деньги или убить свои контейнеры в самый неподходящий момент. -XX:MaxRAMFraction=1 особенно опасно. Java 10+ приносит много улучшений, но все еще нуждается в ручной настройке. Чтобы быть в безопасности, загрузите тест своих вещей.

а также

Наиболее элегантным решением является обновление до Java 10+. Java 10 устарела -XX:+UseCGroupMemoryLimitForHeap (11) и вводит -XX:+UseContainerSupport (12), который заменяет его. Он также вводит -XX:MaxRAMPercentage (13), который принимает значение от 0 до 100. Это позволяет детально контролировать количество оперативной памяти, которую JVM может выделить. Поскольку +UseContainerSupport включен по умолчанию, все должно работать "из коробки".

Ответ 2

В недавнем oracle-jdk-8 (8u191) представлены следующие параметры, позволяющие пользователям контейнеров Docker получить более точный контроль над объемом системной памяти, которая будет использоваться для кучи Java:

-XX:InitialRAMPercentage
-XX:MaxRAMPercentage
-XX:MinRAMPercentage

Три новые опции JVM были добавлены, чтобы позволить пользователям контейнера Docker получить более детальный контроль над объемом системной памяти, которая будет использоваться для Java Heap:

-XX: InitialRAMPercentage -XX: MaxRAMPercentage -XX: MinRAMPercentage Эти параметры заменяют устаревшие формы дроби (-XX: InitialRAMFraction, -XX: MaxRAMFraction и -XX: MinRAMFraction).

См. Https://www.oracle.com/technetwork/java/javase/8u191-relnotes-5032181.html.