Сравнение OpenJ9 и HotSpot Часть 1

Java

OpenJ9 и IBM J9— это реализация JVM, отличная от стандартной JVM Oracle HotSpot. использовать современныеadoptopenjdkБлагодаря готовым образам Docker вы можете легко переключаться и тестировать различные комбинации, а также выбирать подходящую JVM.

Слух кажется правдой, OpenJ9 уже, кажется, опережает HotSpot с точки зрения использования памяти. HotSpot, кажется, имеет преимущество с точки зрения процессора.

OpenJ9

В мире Java большинство людей знакомы с OpenJDK. Это полная реализация JDK, включая реализацию движка HotSpot JVM. Не многие разработчики понимают или пытаются выбрать HotSpot. Расспросив коллег, все они вспомнили название JRockit, но никто не упомянул IBM J9 и/или Eclipse OpenJ9.

я выучилOpenJ9 хорош в управлении памятью, и был оптимизирован для использования в облаке/контейнере. OpenJ9 — это отдельная реализация JVM. Он происходит от IBM Java SDK/IBM J9, который восходит к OTI Technologies Envy Smalltalk (спасибо Дэн Хейдинга!).

По мере роста использования микросервисов (а большинство сервисов в Javaнетособенно маленькие). Я думаю, что это снова станет горячей темой!

контрольная работа

До эпохи Docker сравнивать разные версии JVM было относительно сложно. Вам нужно скачать, установить, написать сценарий и запустить все зависимости. Но многие готовые изображения теперь доступны в Интернете.

Вот мои мысли о том, как протестировать JVM:

  1. Создайте простойSpring Boot заявление

  2. Запускайте приложение в различных образах Docker.

  3. Измерение использования памяти после запуска и сборщика мусора

  4. Измерьте, сколько времени требуется для запуска небольшого теста с интенсивным использованием ЦП

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

Приложение Spring Boot

Созданное мной приложение Spring Boot содержит следующие конечные точки:

  1. Конечная точка REST вызывает GC (постарайтесь сделать это разумным)

  2. Конечная точка REST создает и сортирует большой случайный массив из 1000, возвращает время выполнения (в мс)

Тесты процессора перечислены ниже:

@RestController
public class LoadTestController {

    @RequestMapping("/loadtest")
    public LoadTestResult loadtest() {

        long before = System.currentTimeMillis();

        Random random = new Random();

        for(int i = 0; i < 1000; i++) {
            long[] data = new long[1000000];
            for(int l = 0; l < data.length; l++) {
                data[l] = random.nextLong();
            }
            Arrays.sort(data);
        }

        return new LoadTestResult(System.currentTimeMillis() - before);
    }
}

Является ли этот тест разумным и актуальным… можно спорить бесконечно, но он дает нам некоторое базовое представление о том, какой презентации мы можем от него ожидать. Если слухи об увеличении памяти верны, может ли это быть ударом по производительности? Существуют ли компромиссы производительности?

JVM-образ

Я решил протестировать следующие изображения.

Сначала у нас есть версия 8/9/10/11 (облегченная)openjdkЗеркало:

  • openjdk:8-slim

  • openjdk:9-slim

  • openjdk:10-slim

  • openjdk:11-slim

Далее идет версия 8/9/10adoptopenjdkЗеркало:

  • adoptopenjdk/openjdk8

  • adoptopenjdk/openjdk9

  • adoptopenjdk/openjdk10

После этого OpenJ9, такжеadoptopenjdkПредоставляется для версии 8/9 вместе с ежедневными сборками, выпущенными для 9 (об этом см. мой предыдущий пост в блоге):

  • adoptopenjdk/openjdk8-openj9

  • adoptopenjdk/openjdk9-openj9

  • adoptopenjdk/openjdk9-openj9:nightly

В то же время я решил также представить собственный образ J9 от IBM:

  • ibmcom/ibmjava:8-jre

Протестируйте с помощью Докера

После сборки приложения Spring Boot я запускал каждый образ Docker с помощью следующей команды:

docker run -it -v /Projects/temp/spring-boot-example:/app/spring-boot-example -p 8080:8080 IMAGE_NAME /bin/bash

Я сопоставил каталог проекта «spring-boot-example» с «/apps/spring-boot-example», после чего я могу запустить файл JAR в контейнере. В то же время я перенаправляю порт 8080 на свой хост, чтобы я мог вызывать эти конечные точки.

Далее внутри контейнера я запустил приложение Spring Boot:

java -jar /app/spring-boot-example/target/spring-boot-example-0.0.1-SNAPSHOT.jar

Подождите некоторое время, несколько раз вызовите конечную точку и выполните GC, после чего я измеряю использование памяти.

Затем я вызвал конечную точку «/ loadtest», содержащую тест сортировки массива, и дождался результата.

тест памяти

Вот результаты использования памяти для примера приложения Spring Boot:

Во-первых, вы можете видеть, что использование памяти в Java 8 значительно выше, чем в Java 9 и 10.

Но самое удивительное — это объем памяти, используемый OpenJ9 и J9, если сравнивать Java8 и OpenJ9, то последний почти в 4 раза больше первого. Я поражен, как это произошло? Теперь мы почти можем назвать сервисы Spring Boot микро!

Я также пытался запустить некоторый код Spring Boot в производстве (не только простые примеры), и с ними я увидел улучшение на 40-50% сокращения использования памяти.

Тесты процессора

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

Отсортируйте 1000 массивов с 1000000 случайных длинных значений. Это занимает около 100 секунд, что должно дать JVM достаточно времени для настройки и оптимизации. Я вызывал тест дважды для каждого тестового изображения. Я записал второй раз, чтобы попытаться исключить время горячей загрузки.


Из графика видно, что зеркалирование J9 и OpenJ9 действительно медленное, самое быстрое — не более 18%. В этом конкретном тестовом примере Java 8 превосходит подавляющее большинство реализаций Java 9 (кроме OpenJ9).

Что дальше?

В продакшне мой текущий проект имеет больше проблем с ЦП (переполнение памяти при частых запусках, а загрузка ЦП составляет 1-2%), чем проблем с памятью. Мы обязательно перейдем на использование OpenJ9 в ближайшем будущем.

Во время тестирования мы столкнулись с некоторыми проблемами:

  1. Hessian: (двоичный протокол) имеет встроенное предположение, что System.identityHashCode всегда возвращает положительное число. Это верно для HotSpot, но OpenJ9/J9 также может возвращать отрицательные числа. Это открытая проблема, проект Hessian не исправлял ее несколько лет, похоже, что она не обслуживается? Так что наше решение - держаться подальше от Хессиана.

  2. Instana: нам нравится наш инструмент мониторинга Instana, но у него возникают проблемы с подключением прокси-сервера к OpenJ9/J9. К счастью, разработчики Instana помогли нам найти ошибку и исправили ее (и автообновление, вау!)

Открытые вопросы, которые я не заметил:

  1. Можете ли вы по-прежнему получать/использовать jmap/hprof и т. д. для информации в OpenJ9?

  2. Как он будет работать в более длительной производственной среде?

  3. Найдем ли мы другие странные ошибки? Это сложно...

Вы пробовали использовать OpenJ9/J9? Поделитесь своим мнением в разделе комментариев!