CRaC (Coordinated Restore at Checkpoint) — это проект OpenJDK, разработанный Azul для решения проблемы «медленного» запуска виртуальной машины Java в микросервисной среде.
Когда JVM запускает код вашего приложения, она выполняет такие действия, как интерпретация, компиляция и оптимизация кода, чтобы ваше приложение работало как можно быстрее при заданной рабочей нагрузке. Это здорово, но может занять некоторое время, и особенно при запуске короткоживущих микросервисов, вы не хотите ждать, пока JVM создаст наиболее оптимизированный код.
В механизме восстановления контрольной точки (checkpoint‑restore) нет ничего нового, и большинство из вас уже знают и используют его ежедневно.
Если вы работаете на ноутбуке и закрываете крышку, операционная система обнаруживает это и сохраняет текущее состояние на диск. Как только вы снова открываете крышку, операционная система восстанавливает сохраненное состояние с диска.
CRaC предоставляет тот же механизм, но для JVM и вашего запущенного приложения.
Вы запускаете свое приложение, применяете к нему некоторую рабочую нагрузку (чтобы убедиться, что важные части вашего кода будут затронуты и оптимизированы JVM), а затем создаете контрольную точку. Это приведет к закрытию всех открытых ресурсов, таких как открытые файлы и сокетные соединения, а затем сохранит состояние JVM, включая ваше приложение, на диск.
После этого вы сможете восстанавливать состояние JVM, включая состояние вашего приложения, из этой сохраненной контрольной точки так часто, как вам захочется.
Таким образом, CRaC не только решает проблему времени запуска, но и может решить проблему времени разогрева приложения, поскольку вы можете создавать контрольную точку в любое время.
Подробнее про CRaC
Если вы хотите узнать больше о проекте, вот несколько сообщений в блогах с более подробными объяснениями:
Видео про CRaC
На YouTube вы также можете найти несколько записей моих сессий и сессий моего коллеги Саймона Риттера. Вот только два из них:
Страница CRaC на GitHub
Если вы хотите узнать больше о реализации или скачать сборку OpenJDK, включающую поддержку CRaC, вы можете заглянуть на созданную нами страницу на GitHub.
Подготовка
Идея заключается в том, чтобы иметь приложение или сервис, состоящий из одного исполняемого файла JAR.
План состоит в том, чтобы заставить вас использовать ваше собственное приложение для этого теста, но если вы просто хотите поиграть с CRaC, вы также можете использовать одну из моих демонстраций, которые можно найти здесь.
Примечание. CRaC доступен только для Linux, работающего на машине x64 (Intel/AMD), что является конфигурацией, которая в основном используется современными облачными провайдерами.
Создайте образ докера
Вам нужно приложение в виде запускаемого JAR-файла.
Затем нужно создать Dockerfile. Следующий файл — это минимальный файл, необходимый для запуска вашего приложения в контейнере Docker.
FROM ubuntu:20.04
ENV JAVA_HOME /opt/jdk
ENV PATH $JAVA_HOME/bin:$PATH
RUN apt-get update -y
ADD "https://github.com/CRaC/openjdk-builds/releases/download/17-crac%2B3/openjdk-17-crac+3_linux-x64.tar.gz" $JAVA_HOME/openjdk.tar.gz
RUN tar --extract --file $JAVA_HOME/openjdk.tar.gz --directory "$JAVA_HOME" --strip-components 1; rm $JAVA_HOME/openjdk.tar.gz;
RUN mkdir -p /opt/crac-files
COPY build/libs/MY-APP.jar /opt/app/MY-APP.jar
Теперь мы можем выполнить команду
docker build -t myapp_on_crac .
создания образа докера.
Запустите ваше приложение в docker-контейнере
Запустите ваш docker-контейнер с помощью команды:
docker run -it --privileged --rm --name my_app_on_crac my_app_on_crac
В docker-контейнере выполните команды:
cd /opt/app
java -XX:CRaCCheckpointTo=/opt/crac-files -jar MY-APP.jar
Запишите PID программы.
Оставьте окно shell открытым и приложение запущенным.
Создайте контрольную точку
Откройте другое окно shell.
В этом окне выполните:
docker exec -it -u root my_app_on_crac /bin/bash
Теперь вам решать, когда вы хотите создать контрольную точку (например, применить некоторую рабочую нагрузку к вашему приложению, чтобы убедиться, что все скомпилировано и оптимизировано).
Возьмите PID, который вы отметили в другом окне shell, и создайте контрольную точку, выполнив команду:
jcmd PID JDK.checkpoint
Если все в порядке, вы должны увидеть, что в первом окне shell была создана контрольная точка, и ваше приложение было закрыто.
Теперь docker-контейнер, запущенный в первом окне shell, содержит контрольную точку в папке
/opt/crac-files
.Теперь вы можете закрыть второе окно shell, выполнив команду
exit
, чтобы вернуться на свою машину.
Зафиксируйте текущее состояние docker-контейнера
Теперь нам нужно сохранить текущее состояние docker-контейнера, включая контрольную точку. Для этого нам нужен идентификатор CONTAINER_ID.
Откройте новое окно shell, выполните команду
docker ps -a
и запишите CONTAINER_ID контейнера, в котором запущено ваше приложение.Выполнив команду:
docker commit CONTAINER_ID my_app_on_crac:checkpoint
Во втором окне shell мы можем зафиксировать текущее состояние контейнера в контрольной точке состояния.
Теперь мы можем остановить docker-контейнер, выполнив команду
exit
в первом окне shell.
Запустите docker-контейнер с контрольной точки
Выполните:
docker run -it --privileged --rm --name my_app_on_crac my_app_on_crac:checkpoint java -XX:CRaCRestoreFrom=/opt/crac-files
Теперь ваше приложение должно запускаться намного быстрее с сохраненной контрольной точки.
Примечание. Вы можете запустить Docker-контейнер также в MacOS или Windows, при условии, что машина, на которой вы его запускаете, имеет архитектуру процессора x64 (Intel/AMD).
Заключительные слова
Если вы экспериментируете с CRaC и столкнулись с проблемами, ПОЖАЛУЙСТА, сообщите нам об этом. Мы только предоставляем решение, но вам нужно его использовать, а мы просто понятия не имеем, что делает ваше приложение.
В случае возникновения проблем лучше всего написать о проблеме на github.