Поделиться через


Контейнеризация приложений Java

В этой статье представлен обзор рекомендуемых стратегий и параметров для контейнеризации приложений Java. При контейнеризации приложения Java внимательно рассмотрите доступное время ЦП контейнера. Затем рассмотрим, сколько памяти доступно как с точки зрения общего объема памяти, так и размера кучи виртуальной машины Java (JVM). В контейнерных средах приложения могут иметь доступ ко всем процессорам и, следовательно, иметь возможность параллельного выполнения нескольких потоков. Однако обычно контейнеры имеют квоту ЦП, которая может регулировать доступ к ЦП.

JVM имеет эвристики, чтобы определить количество "доступных процессоров" на основе квоты ЦП, что может значительно повлиять на производительность приложений Java. Память, выделенная самому контейнеру, и размер области кучи для виртуальной машины JVM так же важен, как процессоры. Эти факторы определяют поведение сборщика мусора (GC) и общую производительность системы.

Контейнеризация нового приложения

При контейнеризации рабочей нагрузки Java для нового приложения необходимо учитывать два момента, когда думаете о памяти.

  • Память, выделенная самому контейнеру.
  • Объем памяти, доступный для процесса Java.

Общие сведения о эргономике JVM по умолчанию

Приложения нуждаются в начальной точке и параметрах. JVM имеет эргономика по умолчанию с предопределенными значениями, основанными на количестве доступных процессоров и объема памяти в системе. Значения по умолчанию, отображаемые в следующих таблицах, используются при запуске JVM без определенных флагов запуска или параметров.

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

Доступные ресурсы GC по умолчанию
Любое количество процессоров
До 1791 МБ памяти
SerialGC
более 2 процессоров
1792 МБ или больше памяти
G1GC

В следующей таблице показан максимальный размер кучи по умолчанию в зависимости от объема доступной памяти в среде, в которой выполняется JVM:

Доступная память Максимальный размер кучи по умолчанию
До 256 МБ 50% объема доступной памяти
256 МБ до 512 МБ ~127 МБ
Более 512 МБ 25% доступной памяти

Начальный размер кучи по умолчанию — 1/64 доступной памяти. Эти значения допустимы для OpenJDK 11 и более поздних версий, а также для большинства дистрибутивов, включая Microsoft Build OpenJDK, Azul Zulu, Eclipse Temurin, Oracle OpenJDK и другие.

Определение памяти контейнера

Выберите объем памяти контейнера, который лучше всего подходит для рабочей нагрузки, в зависимости от потребностей приложения и его отличительных шаблонов использования. Например, если приложение создает графы больших объектов, вероятно, вам потребуется больше памяти, чем для приложений с большим количеством графов объектов.

Подсказка

Если вы не знаете, сколько памяти выделяется, хорошая начальная точка составляет 4 ГБ.

Определение объема памяти кучи JVM

При выделении памяти кучи JVM для JVM требуется больше памяти, чем то, что используется для кучи JVM. Если задать максимальный объем памяти кучи JVM, он никогда не должен совпадать с объемом памяти контейнера, так как это приводит к ошибкам нехватки памяти контейнера (OOM) и крахам контейнера.

Подсказка

Выделите 75% памяти контейнера для кучи памяти JVM.

В OpenJDK 11 и более поздних версиях размер кучи JVM можно задать следующим образом:

Описание Флаг Примеры
Фиксированное значение -Xmx -Xmx4g
Динамическое значение -XX:MaxRAMPercentage -XX:MaxRAMPercentage=75

Минимальный и начальный размер кучи

Если среда гарантированно имеет определённое количество памяти, зарезервированное для экземпляра JVM, например в контейнерах, необходимо задать минимальный размер кучи (или начальный размер кучи) такого же размера, что и максимальный размер кучи. Этот параметр указывает JVM, что она не должна выполнять задачу освобождения памяти ОС.

Чтобы задать минимальный размер кучи, используйте -Xms для абсолютных сумм или -XX:InitialRAMPercentage процентных сумм.

Это важно

Флаг -XX:MinRAMPercentage, несмотря на то, что сулит имя, используется для настройки максимального процента ОЗУ по умолчанию для систем при наличии до 256 МБ ОЗУ в системе.

Диаграмма, показывающая размер кучи по умолчанию в OpenJDK 17.

Определите, какой сборщик мусора использовать

Ранее вы определили объем памяти кучи JVM для начала. Следующим шагом является выбор вашего Генерального подрядчика. Максимальное количество памяти кучи JVM часто является фактором выбора GC. В следующей таблице описываются характеристики каждой сборки мусора.

Факторы SerialGC ParallelGC G1GC ZGC ShenandoahGC
Число ядер 1 2 2 2 2
Многопоточное нет Да Да Да Да
Размер кучи Java <4 Гбайта <4 Гбайта >4 Гбайта >4 Гбайта >4 Гбайта
Пауза Да Да Да Да (<1 мс) Да (<10 мс)
Накладные расходы Минимальный Минимальный Умеренный Умеренный Умеренный
Эффект задержки хвоста Высоко Высоко Высоко Низкий уровень Умеренный
Версия JDK Все Все JDK 8+ JDK 17+ JDK 11+
Лучше всего подходит для Одно ядро небольших кучи Многоядерная обработка небольших объемов памяти или пакетные рабочие нагрузки с любым размером памяти Откликается на запрос-ответ и взаимодействия с базой данных при средних и больших объемах нагрузки Откликается на запрос-ответ и взаимодействия с базой данных при средних и больших объемах нагрузки Откликается на запрос-ответ и взаимодействия с базой данных при средних и больших объемах нагрузки

Подсказка

Для большинства приложений микросервисов общего назначения начните с Параллельного GC.

Определение количества ядер ЦП

Для любого GC, отличного от SerialGC, рекомендуется использовать два или более ядер виртуального ЦП или по крайней мере 2000m для cpu_limit Kubernetes. Мы не рекомендуем выбирать не более одного ядра виртуального ЦП в контейнерных средах.

Подсказка

Если вы не знаете, сколько ядер для начала, хороший выбор — два ядра виртуального ЦП.

Выбор начальной точки

Рекомендуется начать с двух реплик или экземпляров в средах оркестрации контейнеров, таких как Kubernetes, OpenShift, Azure Spring Apps, Приложения контейнеров Azure и Служба приложений Azure. В следующей таблице приведены рекомендуемые начальные точки для контейнеризации нового приложения Java.

Ядра vCPU Память контейнера Размер кучи JVM GC Копии
2 4 ГБ 75% ParallelGC 2

Используйте следующие параметры JVM:

-XX:+UseParallelGC -XX:MaxRAMPercentage=75

Контейнеризация существующего локального приложения

Если приложение уже работает в локальной среде или на виртуальной машине в облаке, рекомендуется начать с следующей конфигурации:

  • Тот же объем памяти, к которому в настоящее время имеется доступ к приложению.
  • Одинаковое количество ЦП или виртуальных ЦП, которые в настоящее время доступны для приложения.
  • Те же параметры JVM, которые вы используете в настоящее время.

Если комбинация количества ядер виртуальных ЦП и памяти контейнера недоступна, выберите ближайший вариант, округляя в большую сторону количество ядер виртуальных ЦП и объем памяти контейнера.

Дальнейшие шаги

Теперь, когда вы понимаете общие рекомендации по контейнеризации приложений Java, перейдите к следующей статье, чтобы установить базовый план контейнеризации: