Контейнеризация приложений 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 можно задать следующим образом:

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

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

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

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

Важно!

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

Chart showing the default heap size on OpenJDK 17.

Определение используемой сборки GC

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

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

Совет

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

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

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

Совет

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

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

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

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

Используемые параметры JVM: -XX:+UseParallelGC -XX:MaxRAMPercentage=75

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

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

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

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

Следующие шаги

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