Недавно я начал играть с Graal VM. Что такое Грааль ВМ? Чтобы процитировать их сайт напрямую:
GraalVM — это универсальная виртуальная машина для запуска приложений, написанных на языках JavaScript, Python, Ruby, R, JVM, таких как Java, Scala, Kotlin, Clojure, и языков на основе LLVM, таких как C и C ++.
GraalVM устраняет изоляцию между языками программирования и обеспечивает совместимость в общей среде выполнения.
С точки зрения непрофессионала, Graal VM позволяет языкам JavaScript, Python, Ruby, R, JVM-языкам, таким как Java, Scala, Kotlin, Clojure, общаться друг с другом , тем самым устраняя изоляцию между этими языками.
Но, как разработчик платформы Java / JVM, меня больше интересует способность Graal VM заранее скомпилировать Java для запуска приложения Java как собственного приложения. Дополнительно:
«GraalVM Native Image позволяет вам заблаговременно скомпилировать код Java в отдельный исполняемый файл, называемый
собственным образом ».
"native-image
это утилита, которая обрабатывает все классы вашего приложения и их зависимости, в том числе из JDK. Он статически анализирует эти классы, чтобы определить, какие классы и методы достижимы и используются во время выполнения приложения. Затем он передает весь этот достижимый код в качестве входных данных компилятору GraalVM, который заранее компилирует его в собственный двоичный файл ».
Ключевые преимущества компиляции Java-приложения AOT в собственный двоичный код:
- Скорость запуска
- Уменьшенный объем памяти
Например, вот приложение Micronaut: https://github.com/RaviH/graal-micronaut
Когда я пытаюсь запустить флягу, для запуска требуется около 1,3 с:
$ java -jar target/graal-micronaut-0.1.jar
18:30:22.244 [main] INFO io.micronaut.runtime.Micronaut - Startup completed in 1320ms. Server Running: http://localhost:8080
Но когда я создаю собственный образ, он запускается через 29 мс (против 1,3 с) — в 45 раз быстрее время загрузки.
# rhasija ~/dev/projects/tmp/graal-micronaut on git:master x C:130
$ native-image -jar target/graal-micronaut-0.1.jar
Build on Server(pid: 5608, port: 50229)
[graal-micronaut:5608] classlist: 3,788.29 ms
[graal-micronaut:5608] (cap): 1,547.58 ms
[graal-micronaut:5608] setup: 2,041.59 ms
[graal-micronaut:5608] (typeflow): 27,169.03 ms
[graal-micronaut:5608] (objects): 32,584.30 ms
[graal-micronaut:5608] (features): 1,562.28 ms
[graal-micronaut:5608] analysis: 63,945.36 ms
[graal-micronaut:5608] universe: 1,593.43 ms
[graal-micronaut:5608] (parse): 4,368.97 ms
[graal-micronaut:5608] (inline): 9,400.59 ms
[graal-micronaut:5608] (compile): 36,820.75 ms
[graal-micronaut:5608] compile: 53,848.37 ms
[graal-micronaut:5608] image: 4,955.53 ms
[graal-micronaut:5608] write: 1,971.52 ms
[graal-micronaut:5608] [total]: 132,379.50 ms
# rhasija ~/dev/projects/tmp/graal-micronaut on git:master x
$ ./graal-micronaut
18:36:13.776 [main] INFO io.micronaut.runtime.Micronaut - Startup completed in 29ms. Server Running: http://localhost:8080
Кроме того, исходный образ занял 14 МБ памяти (по сравнению с 387 МБ на основе Java-приложения) — примерно 3% памяти, занимаемой Java-приложением. Это круто.
Java-приложение Micronaut:13068 java 0.1 00:03.00 23 1 84 387M 0B 0B 13068 5096
Родное изображение:13136 graal-micron 0.0 00:00.03 3 1 33 14M 0B 0B 13136 5096
Ниже приведены показатели производительности для конечной точки:
Для родного двоичного файла Graal VM:
$ bombardier -n 100000 -c 100 "http://localhost:8080/simple"
Bombarding http://localhost:8080/simple with 100000 request(s) using 100 connection(s)
100000 / 100000 [=========================================================] 100.00% 18s
Done!
Statistics Avg Stdev Max
Reqs/sec 5308.20 1376.18 9776.58
Latency 18.70ms 23.93ms 305.78ms
HTTP codes:
1xx - 0, 2xx - 100000, 3xx - 0, 4xx - 0, 5xx - 0
others - 0
Throughput: 16.31MB/s%
$ bombardier -n 100000 -c 100 "http://localhost:8080/simple"
Bombarding http://localhost:8080/simple with 100000 request(s) using 100 connection(s)
100000 / 100000 [=============================================================================================] 100.00% 19s
Done!
Statistics Avg Stdev Max
Reqs/sec 5164.61 1269.64 11265.72
Latency 19.22ms 19.82ms 249.97ms
HTTP codes:
1xx - 0, 2xx - 100000, 3xx - 0, 4xx - 0, 5xx - 0
others - 0
Throughput: 15.87MB/s%
$ bombardier -n 100000 -c 100 "http://localhost:8080/simple"
Bombarding http://localhost:8080/simple with 100000 request(s) using 100 connection(s)
100000 / 100000 [=============================================================================================] 100.00% 19s
Done!
Statistics Avg Stdev Max
Reqs/sec 5041.83 1283.07 10297.43
Latency 19.66ms 22.36ms 310.20ms
HTTP codes:
1xx - 0, 2xx - 100000, 3xx - 0, 4xx - 0, 5xx - 0
others - 0
Throughput: 15.51MB/s%
Для приложения Java :
$ bombardier -n 100000 -c 100 "http://localhost:8080/simple"
Bombarding http://localhost:8080/simple with 100000 request(s) using 100 connection(s)
100000 / 100000 [=============================================================================================] 100.00% 17s
Done!
Statistics Avg Stdev Max
Reqs/sec 5629.80 1057.21 13696.04
Latency 17.70ms 8.91ms 182.28ms
HTTP codes:
1xx - 0, 2xx - 100000, 3xx - 0, 4xx - 0, 5xx - 0
others - 0
Throughput: 17.15MB/s%
$ bombardier -n 100000 -c 100 "http://localhost:8080/simple"
Bombarding http://localhost:8080/simple with 100000 request(s) using 100 connection(s)
100000 / 100000 [=============================================================================================] 100.00% 14s
Done!
Statistics Avg Stdev Max
Reqs/sec 7034.21 592.21 15347.18
Latency 14.22ms 2.91ms 65.69ms
HTTP codes:
1xx - 0, 2xx - 100000, 3xx - 0, 4xx - 0, 5xx - 0
others - 0
Throughput: 21.45MB/s%
# rhasija ~/dev/projects/tmp/graal-micronaut on git:master x
$ bombardier -n 100000 -c 100 "http://localhost:8080/simple"
Bombarding http://localhost:8080/simple with 100000 request(s) using 100 connection(s)
100000 / 100000 [=============================================================================================] 100.00% 14s
Done!
Statistics Avg Stdev Max
Reqs/sec 7060.21 2076.69 61322.98
Latency 14.31ms 2.79ms 57.63ms
HTTP codes:
1xx - 0, 2xx - 100000, 3xx - 0, 4xx - 0, 5xx - 0
others - 0
Throughput: 21.31MB/s%
Приложение Java работало стабильно лучше.
Детали :
$ mvn -v
Apache Maven 3.6.0 (97c98ec64a1fdfee7767ce5ffb20918da4f719f3; 2018-10-24T11:41:47-07:00)
Maven home: /Users/rhasija/.sdkman/candidates/maven/current
Java version: 1.8.0_202, vendor: Oracle Corporation, runtime: /Users/rhasija/.sdkman/candidates/java/1.0.0-rc-16-grl/jre
Default locale: en_US, platform encoding: UTF-8
OS name: "mac os x", version: "10.13.6", arch: "x86_64", family: "mac"
Чтобы получить больше информации об этом, я попросил людей GraalVM, и Олег Селаев вернулся с этой информацией:
«Native Image действительно предлагает превосходные издержки запуска / памяти? Режим JVM. «
«Кроме того, если вы используете GraalVM Enterprise, вы можете обеспечить
--pgo-instrument
создание инструментированного двоичного файла и использовать его профиль для создания (с--pgo
) более производительного собственного образа.
Нижняя граница
Я могу ошибаться, но это то, что я узнал: GraalVM отлично подходит для приложений быстрого запуска / lamdas, которые выполнят свою работу и сразу же будут закрыты, или для приложений, где производительность не является проблемой. Но для долго работающих приложений, которые должны работать с высокой нагрузкой, Java-приложения (из-за JIT-компилятора) все же лучше. Это может измениться в будущем, но сейчас, похоже, это так.
Мысли / обратная связь? Позвольте мне знать в комментариях ниже.