Статьи

Более быстрый запуск Java с восстановлением контрольной точки на главном

Виртуальная машина Java предоставляет управляемую среду выполнения для приложений, которые были скомпилированы в байт-коды (но, возможно, не обязательно были написаны на Java). Это дает многочисленные преимущества разработчикам приложений и часто повышает производительность по сравнению со статически скомпилированным кодом для конкретной платформы. JVM автоматически выполняет выделение и восстановление памяти через сборщик мусора (GC), уменьшая вероятность утечек памяти. Компиляция Just-in-Time (JIT) предоставляет возможность «писать один раз, запускать где угодно», устраняя необходимость в создании отдельных двоичных версий приложения для каждой поддерживаемой платформы.

Эти преимущества не совсем без затрат, однако. Хотя общая скорость приложения, работающего на JVM, в конечном итоге может быть выше, требуется время на прогрев , так как часто используемые методы компилируются и оптимизируются. Каждый раз, когда приложение запускается, должно выполняться одно и то же профилирование, анализ и компиляция, даже если приложение используется идентично.

Zing JVM использует JIT-компилятор Falcon вместо старого C2 JIT и ReadyNow! технология записи профиля, которую можно использовать при перезапуске приложения.

Сборка Azul Zulu OpenJDK теперь включает в себя аналогичный набор технологий, который мы называем Checkpoint / Restore at Main (CRaM).

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

  1. Приложение используется, как обычно, и выполняет все необходимые функции. Приложение завершается при выходе из метода main (). В этот момент все данные из запуска приложения записываются. Никаких изменений не требуется для кода приложения; добавление флага JVM -Zcheckpoint — это все, что требуется.
  2. Приложение используется согласно сценарию 1 выше, но завершается вызовом System.exit (). Опять же, никаких изменений в коде приложения не требуется, но в этом случае должен использоваться флаг JVM -Dcom.azul.System.exit.doCheckpointRestore = true.
  3. В этом сценарии разработчик выбирает конкретную точку в коде приложения, где он хотел бы создать контрольную точку. Необходимо внести изменения в код приложения; вызов метода, Dcom.azul.System.tryCheckpointRestore (), размещается там, где это необходимо. Это полезно для приложений, которые не завершаются. Вызов игнорируется, если для JVM не указан флаг -Zcheckpoint. Доступен дополнительный флаг -XX: CRTrainingCount, позволяющий приложению обрабатывать более одной транзакции перед записью контрольной точки.

Контрольная точка — это сложный снимок состояния приложения при его создании. Включает в себя следующую информацию:

  • Внутреннее представление JVM классов Java. Каждый раз, когда приложение запускается, оно должно прочитать требуемые классы и создать свое собственное представление каждого класса с инициализированными данными.
  • Код, сгенерированный компиляторами JVM JIT, C1 и C2. Из-за того, как этот код используется повторно, необходимо отключить определенные оптимизации, чтобы разрешить повторное использование кода в производственном цикле.
  • Инициализированные системные классы. Это классы из базовых библиотек классов и не зависят от кода приложения.
  • Определенные объекты Java из кучи, связанные с запуском приложения.

Существуют строгие ограничения на использование контрольной точки для производственного цикла. Контрольная точка тесно связана с платформой, используемой для учебного прогона, и включает информацию очень низкого уровня, такую ​​как страницы памяти из отображенных системных библиотек, таких как libc. Контрольная точка не будет работать, если будут внесены изменения в системные библиотеки, JDK или код приложения до выполнения производственного запуска. Контрольные точки должны быть общими только для компьютеров, работающих с одним и тем же аппаратным и программным стеком.

Чтобы использовать контрольную точку для производственного прогона, вы должны использовать такую ​​командную строку:

1
java -Zrestore myAppClass <application arguments>

Ранее сохраненные данные контрольной точки будут использоваться для минимизации, насколько это возможно, времени прогрева, связанного с приложением. Следует отметить пару важных моментов:

  • Во время производственного цикла код может быть перекомпилирован как обычная часть процесса компиляции JIT. В отличие от тренировочного прогона, все оптимизации, доступные для JIT, будут включены.
  • Приложение должно быть запущено из того же каталога, в котором был создан обучающий прогон. Это часть состояния контрольно-пропускного пункта.
  • Не следует использовать флаги командной строки JVM. Тренировочный прогон привязан к флагам командной строки, используемым при его создании, и они автоматически устанавливаются во время производственного прогона. Их изменение может сделать недействительной информацию в контрольно-пропускном пункте.

В настоящее время функциональность CRaM предназначена для встраиваемых приложений, где возможность запуска с оптимальной скоростью при запуске является жизненно важной. Таким образом, поддерживаемыми платформами для CRaM являются только 32-битные процессоры Arm, работающие под управлением Linux с ядром 3.5 или выше и glibc версии 2.13 или выше. CRaM включает утилиту cr-compat-checker, которую можно использовать для проверки соответствия устройства этим требованиям.

Чтобы определить, подходит ли CRaM для приложения, важно понять, как он меняет профиль производительности приложения. CRaM предназначен для сокращения времени, необходимого для достижения точки, где была создана контрольная точка. Выполнение с этого момента будет неизменным независимо от того, была ли использована контрольная точка или нет. Если посмотреть на производительность Java-приложения, его можно разделить на две части: время запуска JVM, то есть время, чтобы добраться до точки входа main (); и время, идущее от main (). При использовании CRaM время, необходимое для доступа к main (), будет больше, но время, необходимое для достижения места создания контрольной точки, будет меньше.

Чтобы это было легче понять, полезна диаграмма:

В качестве примера рассмотрим простое приложение Spring Boot.

Без использования CRaM время main () составляло 2 секунды, а время от входа в main () до полностью инициализированного приложения, готового к обработке транзакций, составляло 31 секунду. Следовательно, время, необходимое для обработки транзакции, составило 33 секунды.

Взяв контрольную точку, используя CRaM для запуска приложения, время до main () было увеличено до 3 секунд. Однако время от ввода main () до полной инициализации составило всего 18 секунд. Это сокращает время, необходимое для обработки транзакции, до 21 секунды, что значительно быстрее.

Как видите, CRaM может существенно повлиять на эффективность приложений, которые должны быть готовы к выполнению задач как можно быстрее. Это особенно важно во встроенных приложениях, где ресурсы ограничены, и устройства могут нуждаться в перезапуске чаще, чем обычный сервер.

В настоящее время Азул проводит бета-тестирование CRaM. Если вы заинтересованы быть частью этого, пожалуйста, свяжитесь с нами для получения дополнительной информации.

КОНТАКТ AZUL ДЛЯ ДОПОЛНИТЕЛЬНОЙ ИНФОРМАЦИИ