Русский
Русский
English
Статистика
Реклама

Graalvm

Опыт сопряжения Java, JavaScript, Ruby и Python в одном проекте посредством GraalVM

25.12.2020 04:13:23 | Автор: admin
В прошлом месяце вышла стабильная LTS-версия многоязычной среды выполнения GraalVM 20.3.0 от корпорации Oracle и мне захотелось испробовать её для решения какой-нибудь интересной практической задачи. Для тех кто не в курсе, приведу краткое описание этой новой платформы. GraalVM позволяет использовать в едином окружении различные популярные языки программирования и обеспечивает их разностороннее взаимодействие в рамках некоторой общей среды выполнения.


Схематическое изображение архитектуры GraalVM из официальной документации.

Добавление новых языков в GraalVM осуществляется с помощью специального фреймворка Truffle, выполненного в виде библиотеки Java. Фреймворк предназначен для создания реализаций языков программирования в качестве интерпретаторов для самомодифицируемых абстрактных синтаксических деревьев (AST). При желании на его основе можно создать собственный язык, в официальных репозиториях GraalVM подробно рассмотрен пример реализации такого проекта под названием SimpleLanguage. Интерпретаторы, которые были написаны с использованием фреймворка Truffle, будут автоматически использовать GraalVM как JIT-компилятор непосредственно для самой реализации языка запускаемой на JVM-платформе и, соответственно, иметь возможность взаимодействия и двустороннего обмена данными в одном и том же пространстве памяти посредством специально разработанного протокола и программного интерфейса Polyglot API.

Платформа GraalVM вместе с исполняемой программой на смеси самых разных языков может быть представлена в виде автономного и самодостаточного исполняемого файла, либо работать поверх OpenJDK, Node.js или даже внутри Oracle Database.

На текущий момент сразу из коробки поддерживаются следующие языки программирования и технологии:

  • Java, Kotlin, Scala и другие языки JVM-платформы.
  • JavaScript вкупе с платформой Node.js и сопутствующим инструментарием.
  • C, C++, Rust и другие языки, которые могут быть скомпилированы в LLVM bitcode.

Помимо этого, с помощью встроенного пакетного менеджера в дистрибутив GraalVM можно добавить поддержку:

  • Python
  • Ruby
  • R
  • WebAssembly

Стоит заметить, что реализации языков и технологий из списка выше пока являются экспериментальными и в настоящее время не рекомендуются для производственного использования. Но для моей задачи это не столь принципиально.

Кроме того, посредством ahead-of-time (AOT) компиляции имеется возможность создавать автономные исполняемые файлы, называемые нативными образами, которые используют не классическую Java VM, а более специализированную Substrate VM, реализующую компактную среду выполнения. В итоге программы запускаются значительно быстрее и расходуют гораздо меньше оперативной памяти. Но при этом теряются некоторые преимущества just-in-time (JIT) компиляции, доступной на классических платформах. Для формирования подобных нативных образов в большинстве случаев требуются значительные ресурсы CPU и десятки гигабайт оперативной памяти, поэтому их создание лучше всего производить на каких-нибудь мощных сборочных серверах или рабочих станциях.

Корпорация Oracle в настоящее время позиционирует GraalVM как единую и идеальную платформу для создания различных микросервисов. При этом она уже имеет влияние на развитие классического OpenJDK. Например, встраиваемый движок JavaScript под названием Nashorn уже удалён из JDK 15, а в качестве его замены предлагается попробовать именно GraalVM. Неизвестно, как дальше будут развиваться события и будет ли GraalVM в будущем предлагаться в качестве рекомендуемой JVM-платформы по умолчанию, но судя по весьма активному развитию и маркетинговому продвижению в последнее время, Oracle настроен вполне серьёзно. Так что время покажет.

Для конечного использования предлагаются две редакции: бесплатная GraalVM Community и платная GraalVM Enterprise, отличия между которыми описаны на этой страничке официального сайта GraalVM. В основном они сводятся к обеспечению лучшей производительности, меньшего потребления оперативной памяти и официальной поддержке от специалистов корпорации Oracle в платной версии. В этой статье я буду ориентироваться только на возможности GraalVM Community, распространяемой свободно.

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

Содержание:


1. Подсветка синтаксиса фрагментов кода на стороне сервера
2. Создание простейшего прототипа
3. Установка GraalVM и сопутствующих библиотек, запуск прототипа
4. От прототипа к готовому сервису
5. Подведём итоги

1. Подсветка синтаксиса фрагментов кода на стороне сервера


Когда-то давно мне стало жутко интересно, какими технологиями крупные хостеры IT-проектов вроде GitHub, Gitorious и Bitbucket подсвечивают наш исходный код на своих серверах. Проведя некоторое исследование, я пришёл к следующим результатам:

  1. Bitbucket использует библиотеку Pygments на языке программирования Python.
  2. GitHub использует Albino, обёртку библиотеки Pygments для языка программирования Ruby.
  3. Gitorious использует Makeup, тоже по своей сути обёртку библиотеки Pygments для Ruby.

Таким образом, я пришёл к выводу, что все крупные компании использовали и активно развивали библиотеку Pygments, благодаря чему этот проект сегодня поддерживает наибольшее количество языков программирования, которые он может подсвечивать.

Шло время и недавно я решил снова перепроверить чем же сейчас пользуются крупные хостеры исходного кода. За это время Gitorious был куплен GitLab'ом, который в итоге стал новым крупным и популярным сервисом. На сей раз получились такие результаты:

  1. Bitbucket как использовал библиотеку Pygments ранее, так и продолжает её использовать.
  2. GitHub отказался от использования обёртки Albino и перешёл на новую библиотеку Linguist. Однако, Linguist только детектирует язык в исходных файлах, а сам процесс подсветки выполняется какой-то другой библиотекой с закрытым исходным кодом, принадлежащей GitHub.
  3. GitLab применяет библиотеку Rouge на языке программирования Ruby, свободную от использования обёрток, но сохранившую некоторую совместимость с Pygments.

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

Особняком ещё стоит библиотека Highlight.js на языке программирования JavaScript, получившая огромную популярность и широкое распространение на самых разнообразных сайтах и сервисах. Её применяют в основном чтобы подсвечивать код на стороне клиента, но никто не запрещает использовать эту библиотеку и для подсветки на стороне сервера.

Если бы вы писали сайт на каком-либо языке JVM-стека вкупе с каким-нибудь популярным веб-фреймворком и перед вами бы стояла задача реализовать серверную подсветку синтаксиса различных фрагментов кода, то у вас бы испортилось настроение. К большому сожалению, JVM-платформа не обзавелась такими библиотеками, как Pygments, Rouge и Highlight.js, которые поддерживают сотни языков программирования. Все известные мне попытки портирования Pygments на Java на сегодня по сути заброшены и поэтому вам для выполнения этой задачи пришлось бы делать такие же обёртки над чужеродными библиотеками, которые были описаны выше.

Альтернатива видится в использовании Jython, JRuby или Nashorn, то бишь внешних реализаций Python, Ruby и JavaScript для платформы JVM. Но с ними не всё так гладко, как хотелось бы. Во-первых, размер вашего JAR-файла или WAR-файла и время его запуска существенно увеличится. Во-вторых, некоторые библиотеки предоставляют реализации версий языков далеко не первой свежести, например, Jython так и остался на Python 2, который уже устарел и новые версии Pygments на нём просто не работают. В-третьих, установка сторонних библиотек внутрь конечного файла для развёртывания в некоторых случаях далеко не так тривиальна и сопровождается грудой различных проблем и точек отказа.

В итоге все эти недостатки усложняют решение довольно тривиальной задачи. И именно в этот момент на сцену выходит GraalVM, который позволяет достаточно просто совмещать и склеивать между собой код и компоненты на различных языках программирования. Платформу JVM со своей кучей библиотек мы можем обогатить батарейками из экосистем других языков и использовать эксклюзивные библиотеки, альтернативы которых недоступны на нашей платформе.

Поэтому у меня появилась идея создать демонстрационный сервис с использованием GraalVM, который бы объединял в себе возможность работы различных библиотек для подсветки синтаксиса на стороне сервера. Он бы неплохо продемонстрировал готовность и удобство сопряжения нескольких языков программирования в рамках платформы GraalVM.

<< Перейти к содержанию

2. Создание простейшего прототипа


После обозначения практической задачи я приступил к созданию простейшего прототипа, который бы демонстрировал нужные мне возможности и подсвечивал скармливаемые ему фрагменты исходного кода. Я выбрал три библиотеки для использования в своём проекте:

  • Highlight.js на JavaScript, поддерживает ~190 языков программирования.
  • Rouge на Ruby, поддерживает ~205 языков программирования.
  • Pygments на Python, поддерживает ~500 языков программирования.

Их связующим звеном я решил выбрать Java 8, хотя с таким же успехом этот выбор мог быть сделан в сторону Kotlin, Scala или Java 11.

Итак, покопавшись по официальным документациям и гайдам этих библиотек и выяснив как именно подсвечивать с их помощью код, я написал такую вот простенькую консольную программку примерно из ста строк:

Исходный код Highlighter.java
// Highlighter.java, no comments, no checks.// $ javac Highlighter.java// $ jar -cvfe highlighter.jar Highlighter *.class// $ cat hello.py | java -jar highlighter.jar rouge pythonimport org.graalvm.polyglot.Context;import java.io.File;import java.io.FileNotFoundException;import java.util.Scanner;public class Highlighter {  private abstract class Highlight {    protected final Context polyglot =      Context.newBuilder("js", "python", "ruby").allowAllAccess(true).allowIO(true)        .build();    protected abstract String language();    protected abstract String renderHtml(String language, String rawCode);    protected String execute(String sourceCode) {      try {        return polyglot.eval(language(), sourceCode).asString();      } catch (RuntimeException re) { re.printStackTrace(); }      return sourceCode;    }    protected void importValue(String name, String value) {      try {        polyglot.getBindings(language()).putMember(name, value);      } catch (RuntimeException re) { re.printStackTrace(); }    }  }  private class Hjs extends Highlight {    @Override    protected String language() { return "js"; }    @Override    public String renderHtml(String language, String rawCode) {      importValue("source", rawCode);      String hjs = "";      try {        hjs = new Scanner(new File("highlight.min.js")).useDelimiter("\\A").next();      } catch (FileNotFoundException fnfe) { fnfe.printStackTrace(); }      final String renderLanguageSnippet =        hjs + "\n" +        "hljs.highlight('" + language + "', String(source)).value";      return execute(renderLanguageSnippet);    }  }  private class Rouge extends Highlight {    @Override    protected String language() { return "ruby"; }    @Override    public String renderHtml(String language, String rawCode) {      importValue("$source", rawCode);      final String renderLanguageSnippet =        "require 'rouge'" + "\n" +        "formatter = Rouge::Formatters::HTML.new" + "\n" +        "lexer = Rouge::Lexer::find('" + language + "')" + "\n" +        "formatter.format(lexer.lex($source.to_str))";      return execute(renderLanguageSnippet);    }  }  private class Pygments extends Highlight {    @Override    protected String language() { return "python"; }    @Override    public String renderHtml(String language, String rawCode) {      importValue("source", rawCode);      final String renderLanguageSnippet =        "import site" + "\n" +        "from pygments import highlight" + "\n" +        "from pygments.lexers import get_lexer_by_name" + "\n" +        "from pygments.formatters import HtmlFormatter" + "\n" +        "formatter = HtmlFormatter(nowrap=True)" + "\n" +        "lexer = get_lexer_by_name('" + language + "')" + "\n" +        "highlight(source, lexer, formatter)";      return execute(renderLanguageSnippet);    }  }  public String highlight(String library, String language, String code) {    switch (library) {      default:      case "hjs": return new Hjs().renderHtml(language, code);      case "rouge": return new Rouge().renderHtml(language, code);      case "pygments": return new Pygments().renderHtml(language, code);    }  }  public static void main(String[] args) {    Scanner scanner = new Scanner(System.in).useDelimiter("\\A");    if (scanner.hasNext()) {      String code = scanner.next();      if (!code.isEmpty()) {        System.out.println(new Highlighter().highlight(args[0], args[1], code));      }    }  }}


Как видно, в этом фрагменте смешаны четыре разных языка программирования. Утилита принимает на вход stdin в виде текста исходного файла, передаваемые аргументы определяют используемую библиотеку для подсветки и язык фрагмента, затем подсвечивается код и выводится готовый HTML на stdout терминала. Звучит просто и понятно, но для компиляции и запуска этой программы требуется установить GraalVM и сопутствующие пакеты нужных библиотек.

<< Перейти к содержанию

3. Установка GraalVM и сопутствующих библиотек, запуск прототипа


Для экспериментов я выбрал сервер с ванильным CentOS 7, на который без каких либо проблем разворачивается дистрибутив GraalVM.

Рецепт установки платформы у меня получился следующим:

curl -LOJ https://github.com/graalvm/graalvm-ce-builds/releases/download/vm-20.3.0/graalvm-ce-java8-linux-amd64-20.3.0.tar.gz# curl -LOJ https://github.com/graalvm/graalvm-ce-builds/releases/download/vm-20.3.0/graalvm-ce-java11-linux-amd64-20.3.0.tar.gzcd /opt/sudo mkdir graalvmsudo chown `whoami`:`whoami` graalvmcd /opt/graalvm/tar -xvzf ~/graalvm-ce-java8-linux-amd64-20.3.0.tar.gzrm ~/graalvm-ce-java8-linux-amd64-20.3.0.tar.gz

Стоит заметить, что в настоящий момент времени GraalVM 20.3.0 поддерживает только LTS-версии Java 8 и Java 11, поэтому при создании проектов на этой платформе следует помнить об этом и пока забыть про вкусности новых версий Java и JVM-платформ. Итак, после выполнения этих команд в директории /opt/ у вас будет развёрнут GraalVM, но в него ещё нужно добавить поддержку дополнительных компонентов.

Рецепт установки языков программирования в GraalVM и требуемых библиотек подсветки кода таков:

export GRAALVM_HOME=/opt/graalvm/graalvm-ce-java8-20.3.0export JAVA_HOME=$GRAALVM_HOMEexport PATH=$GRAALVM_HOME/bin:$PATHgu install pythongu install ruby# /opt/graalvm/graalvm-ce-java8-20.3.0/jre/languages/ruby/lib/truffle/post_install_hook.shgraalpython -m ginstall install setuptoolscurl -LOJ https://github.com/pygments/pygments/archive/2.7.3.tar.gztar -xvzf pygments-2.7.3.tar.gzcd pygments-2.7.3/graalpython setup.py install --usercd ..rm -Rf pygments-2.7.3/ pygments-2.7.3.tar.gzgem install rougecurl -LOJ https://cdnjs.cloudflare.com/ajax/libs/highlight.js/10.4.1/highlight.min.js

Перед использованием инструментов из дистрибутива GraalVM следует подгрузить нужные нам переменные окружения. При желании их подгрузку можно сделать при старте сервера для определённого пользователя или для всей системы сразу. Утилита gu является неким пакетным менеджером и предназначена для установки, удаления и обновления компонентов GraalVM. Нативные образы я не стал пересобирать, поскольку это достаточно долгий и ресурсоёмкий процесс. Он потребуется только в том случае, если вы захотите сформировать автономный исполняемый файл вашей программы. Пост-установочный скрипт после процесса инсталляции поддержки языка Ruby я тоже не стал выполнять, поскольку библиотека Rouge никак не взаимодействует с сетью и интернетом. Для использования Highlight.js достаточно просто скачать минифицированный файл библиотеки, платформа Node.js здесь никак не задействуется.

Ситуацию с Pygments следует разобрать немного подробнее. В случае с Python, его менеджер пакетов pip доступен лишь в виртуальном окружении virtualenv и для упрощения я решил отказаться от изоляции и использовать способ установки библиотеки Pygments посредством инструмента setuptools и загрузки исходников. Стоит заметить, что постоянные холодные вызовы интерпретатора graalpython довольно ресурсоёмки и на выполнение этих команд потребуется некоторое время, однако после завершения процесса требуемая библиотека будет сразу нам доступна. Кстати, установку и удаление библиотек можно производить и обычным системным pip, который входит в поставку дистрибутива операционной системы. В моём случае использовался CentOS 7, где по умолчанию установлен лишь Python 2, а усложнять инструкцию установкой современного Python 3 мне не хотелось, тем более раз для GraalVM доступна его собственная реализация Python.

Рецепт сборки и запуска консольной программки-прототипа из предыдущего раздела:

export GRAALVM_HOME=/opt/graalvm/graalvm-ce-java8-20.3.0export JAVA_HOME=$GRAALVM_HOMEexport PATH=$GRAALVM_HOME/bin:$PATHjavac Highlighter.javajar -cvfe highlighter.jar Highlighter *.classcat hello.py#!/usr/bin/env pythonprint("Hello, World!")cat hello.py | java -jar highlighter.jar hjs python<span class="hljs-comment">#!/usr/bin/env python</span>print(<span class="hljs-string">"Hello, World!"</span>)cat hello.py | java -jar highlighter.jar rouge python<span class="c1">#!/usr/bin/env python</span><span class="k">print</span><span class="p">(</span><span class="s">"Hello, World!"</span><span class="p">)</span>cat hello.py | java -jar highlighter.jar pygments python<span class="ch">#!/usr/bin/env python</span><span class="nb">print</span><span class="p">(</span><span class="s2">"Hello, World!"</span><span class="p">)</span>

Как видно, всё прекрасно работает! Только не стоит забывать что для Highlight.js требуется положить файлик highlight.min.js рядом с нашей программкой. Использование внутренних ресурсов JAR-файла усложнило бы этот пример, поэтому я решил выбрать именно такой простой способ.

При желании все эти рецепты можно аккуратно завернуть в контейнеры вроде Docker или Podman, кому что нравится. Официальные образы от Oracle с GraalVM вполне себе доступны на том же Docker Hub.

<< Перейти к содержанию

4. От прототипа к готовому сервису


Имея на руках готовый прототип я решил превратить его в простенький демонстрационный сервис, представляющий собой веб-сайт с возможностью сохранения фрагментов исходного кода и выбора библиотеки для запекания подсветки синтаксиса в HTML.

Для реализации этой задачи я взял известный в Java-экосистеме фреймворк Spring, который в настоящее время без особых нареканий работает на GraalVM и даже обозначен на официальном сайте платформы. В качестве проксирующего веб-сервера был выбран Nginx, а для базы данных я использовал PostgreSQL. Для front-end'а мной был выбран несколько устаревший в современном мире, но всё ещё использующийся подход с рендерингом HTML на стороне сервера при помощи шаблонизатора Thymeleaf. В общем, я остановился на одном из самых популярных фреймворков и его сопутствующих инструментах вроде Spring Boot 2.4.1 или Spring Data JPA, которые сильно ускоряют разработку и сокращают рутинный код. Но при этом с GraalVM вы вольны выбирать другие и более легковесные Java-фреймворки, которые больше ориентированы на создание микросервисов. Официальный сайт рекомендует посмотреть на Micronaut и Quarkus, преимущество которых состоит в возможности более лёгкого создания нативных образов из-за меньшего потребления оперативной памяти при их формировании.

Отправку фрагментов кода на веб-сайт я стилизовал под популярный ныне на многих IT-ресурсах язык разметки Markdown:

```python#!/usr/bin/env pythonprint("Hello, World!")```

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


Сервис Code Polyglot с тёмной темой.

Тёмная тема в хакерском стиле создавалась под впечатлением от интерфейса старых мобильных телефонов Motorola на P2K, вроде E398, которые оставили в моей юности приятные и тёплые воспоминания. Оболочка называлась Techno и выглядела следующим образом:

Скриншоты с Motorola E398

Оболочка Techno на Motorola E398.


Надеюсь, вы не станете меня проклинать за моё извращённое чувство прекрасного и безумные умения в вёрстке, ибо я не имею должного опыта веб-разработки. Но если всё-таки станете, то на сайте доступна более нейтральная светлая тема, простой дизайн которой я позаимствовал с похожего сервиса по обмену фрагментами кода: paste.org.ru:


Сервис Code Polyglot со светлой темой.

Итак, прототип потихоньку начал обрастать различной функциональностью для выхода в мир, которую описывать здесь особого смысла я не вижу, всё же эта статья не о том, как быстро сделать подобный веб-сайт с помощью фреймворка Spring Boot. Расскажу лучше о тех проблемах, с которыми мне пришлось столкнуться и которые я попытался преодолеть.

Фрагменты кода на веб-сайте я решил отображать в таблицах, как это делает GitHub, но оказалось что с этим не всё так гладко. Библиотека Highlight.js, например, позиционируется разработчиком как максимально простая и поэтому принципиально не умеет оборачивать фрагменты кода в табличные строки. С другой стороны, генерируемые таблицы Pygments и Rouge слабо совместимы между собой. Поэтому мне пришлось выключать табличное отображение вообще, просто подсвечивать фрагмент кода выбранной библиотекой и построчно оборачивать его в таблицу уже на стороне Java.

Подобный подход привёл ещё к одной проблеме, которую проще всего продемонстрировать на следующем примере:

/* * Многострочный комментарий! */<span class="comment">/* * Многострочный комментарий! */</span><tr><td>1</td><td><span class="comment">/*</td></tr><tr><td>2</td><td> * Многострочный комментарий!</td></tr><tr><td>3</td><td> */</span></td></tr>

Библиотеки Highlight.js и Rouge не оборачивали каждую линию кода в автономные HTML-теги, поэтому при генерации таблицы они разрывались и подсветка кода работала некорректно. Я постарался исправить эту проблему с помощью обычного стека из стандартной библиотеки структур данных в Java. Упрощённый алгоритм выглядит примерно следующим образом: проходим по строке, когда детектим открывающий тег подсветки, то кладём его на стек, а когда детектим закрывающий, то просто убираем последний элемент со стека. Если к концу строки стек не оказывается пустым, то закрываем все открытые теги в текущей строке, а в начале следующей строки открываем те теги, которые остались у нас на стеке. Решение получилось немного топорным, но вполне себе рабочим.

<tr><td>1</td><td><span class="comment">/*</span></td></tr><tr><td>2</td><td><span class="comment"> * Многострочный комментарий!</span></td></tr><tr><td>3</td><td><span class="comment"> */</span></td></tr>

В итоге после обработки подобным алгоритмом пример выше приводится к удобоваримому виду, подсветка начинает работать, а сгенерированный HTML становится корректным. К слову, некоторые похожие сервисы по обмену фрагментов кода имеют схожую проблему, которая так и не решена, поэтому я отписался их владельцам и описал им этот метод исправления.

С последним препятствием я столкнулся уже на слабенькой VPS от Oracle. Оказалось, что экспериментальная поддержка языка программирования Python в GraalVM вкупе с библиотекой Pygments не влазят в мои скромные 1 GB оперативной памяти на виртуальном сервере. Да и сама реализация Python показалась мне ещё несколько сыроватой и медленной, например, иногда в процессе подсветки кода кое-где теряются пробелы и переводы строк, хотя в классическом системном Python всё работает отлично. Поэтому мне пришлось поменять сервер на другой, с более мощным железом и 4 GB RAM на борту.

<< Перейти к содержанию

5. Подведём итоги


В целом, я получил положительный опыт работы с GraalVM и его инструментарием, достаточно быстро смог решить поставленную перед собой задачу сопряжения полезных батареек из экосистем разных языков программирования в рамках одной общей платформы. Из недостатков могу лишь отметить несколько сыроватую и медленную реализацию Python, наверное как раз по этой причине его поддержка до сих пор является в большей степени экспериментальной. А вот с реализацией Ruby, которая тоже является экспериментальной, и с поддержкой JavaScript, который сразу входит в стандартную поставку GraalVM, я не заметил каких-либо проблем, да и работают они вполне себе быстро.

Все свои наработки, рецепты развёртывания и сборки, весь исходный код я разместил в репозитории на GitHub:

github.com/EXL/CodePolyglot

Сам демонстрационный сервис можно потыкать палочкой по этой ссылке:

code.exlmoto.ru

Примечание: из-за наплыва посетителей после публикации статьи может случиться так, что сервер станет недоступным, всё-таки там совсем слабенький канал. Так что прошу меня заранее простить за технические неполадки. Если вам интересен этот проект, то на своих рабочих станциях с кучей оперативной памяти вы можете легко его развернуть и поиграться.

Отдельно стоит поговорить про несколько неудачный опыт создания нативных образов. В тех случаях, когда используются и смешиваются несколько языков программирования, их формирование превращается в пытку. Забегая вперёд сообщу, что для маленького прототипа, который был описан в статье выше, в его нативном образе удалось заставить работать лишь библиотеку Highlight.js вкупе с JavaScript. При попытке добавления других языков программирования автономный исполняемый файл раздувался совсем уж до неприличных размеров в 500 MB и отказывался видеть не только сторонние батарейки, но и стандартные библиотеки Python и Ruby. Копание в переменных окружения и флажках сборки исправило пару проблем, но удобоваримого результата у меня так и не получилось. К тому же, нельзя не упомянуть продолжительное время AOT-компиляции (порядка 10-15 минут), значительное потребление RAM (порядка 20 GB) и ресурсов CPU в процессе сборки.

Если с такими проблемами создания нативного образа я столкнулся на простейшем прототипе, то что уж говорить о моих тщетных попытках преобразования всего сервиса в автономный исполняемый файл. В экосистеме Spring совсем недавно появился экспериментальный проект Spring Native 0.8.5, позволяющий формировать нативные образы сервисов использующих библиотеки Spring. Оригинальные версии Java-библиотек, которые не работают должным образом под Substrate VM, вырезаются или подменяются на патченные, например, в их число входит встраиваемый веб-сервер Tomcat. При этом при сборке нужно ещё сделать некоторые ухищрения и телодвижения вроде правильной настройки Hibernate, подгрузки конфигурационного JSON-файла с описанием некоторой рефлексии и расстановки обязательных флажков для утилиты native-image, которая формирует нативные образы. В качестве системы сборки в Spring Native используется Maven, так как поддержка Gradle находится ещё на начальном этапе развития. В общем, всё выглядит слишком экспериментальным и сырым. В итоге мне удалось добиться корректной сборки нативного образа, но без поддержки каких-либо сторонних языков программирования кроме тех, что доступны на JVM-платформе. При попытках их добавления процесс зависал и ничего полезного так и не происходило в течении 30 минут, после чего я просто останавливал задачу. Далее, при запуске исполняемого файла сыпались ошибки встраиваемого языка SpEL в шаблонах Thymeleaf и я пока отступил от решения этой проблемы.

Для себя я сделал вывод, что AOT-компиляция может быть интересной в том случае, если в проекте не задействован Polyglot API, не смешано множество языков программирования и сервис используется как back-end к чему либо. Вместо Spring для AOT пока лучше использовать более легковесный Quarkus, который как раз опирается на возможность формирования нативных образов в GraalVM. А для проектов, которые используют множество языков и серверные HTML-шаблонизаторы, неплохо работает традиционный подход с JIT-компиляцией и запуском на JVM.

Версии реализаций языков программирования и технологий доступных на платформе GraalVM 20.3.0:

  • Java 8 (1.8.0_272), Java 11 (11.0.9)
  • JavaScript ES2020 (ES11)
  • Ruby 2.6.6
  • Python 3.8.5
  • R 3.6.1
  • LLVM 10.0.0

Некоторые полезные ссылки:

  1. Платформа GraalVM.
  2. Документация GraalVM.
  3. Фреймворк Spring.
  4. Библиотека Pygments.
  5. Библиотека Rouge.
  6. Библиотека Highlight.js.

Надеюсь, мой опыт и эта статья будут полезны тем, кто когда-нибудь заинтересуется платформой GraalVM и её возможностями по использованию множества языков программирования в одном окружении.

P.S. Искренне поздравляю посетителей ресурса Хабр с наступающим 2021 годом, желаю вам ребята исполнения всех ваших желаний и крепкого сибирского здоровья!

P.P.S. Благодарю пользователя zorgrhrd за поддержку! Без него эта статья никогда бы не появилась на свет.

<< Перейти к содержанию
Подробнее..
Категории: Javascript , Ruby , Python , Java , Oracle , Spring , Graalvm , Spring boot , Graal , Polyglot

JPoint 2020 новый формат, новые возможности

04.07.2020 20:20:46 | Автор: admin
С 29 июня по 3 июля 2020 года в онлайн-формате прошла Java-конференция JPoint 2020. Информация о докладах, спикерах, особенностях проведения, впечатления от конференции всё это можно прочитать далее.



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

В предверии летнего блока конференций участники команды JUG Ru Group проделали титанический объём работы как административного, так и технического характера. Была создана онлайн-платформа для трансляции митапов и конференций. Также было проведено множество онлайн-встреч, в том числе Java-серия Первая чашка кофе с JPoint с интервью с участниками программного комитета и спикерами: Владимиром Ситниковым, Маргаритой Недзельской, Тагиром Валеевым, Олегом Докукой, Иваном Углянским и Алексеем Шипилёвым.

В блоге компании JUG Ru Group до летних конференций появилось множество интересных статей и интервью:

В проведении самой конференции произошли изменения:
  • стенды компаний превратились в виртуальную выставку с информацией о компании и возможностью назначения онлайн-встреч;
  • дискуссионные зоны для задания вопросов и общения после докладов тоже стали онлайновыми;
  • изменилось положение ведущих треков они стали играть значительно большую роль, помогая спикерам усилить впечатление от их докладов.

Открытие


Непосредственно перед открытием Алексей Фёдоров предоставил возможность увидеть пультовую Всевластья, помогающую организовать онлайн-конференции. После вводных слов и приветствия спонсоров конфереция была объявлена открытой.



Первый день


Прекрасным предисловием к интервью с James Gosling, отцом языка Java, стала статья, написанная phillennium. Беседу вели и задавали вопросы Андрей Дмитриев и Volker Simonis. Интервью получилось живое и эмоциональное, вызвавшее большой интерес у самого Джеймса. Было задано множество вопросов, от касающихся подробностей его прошлых проектов до отношения к популярному в настоящее время JVM-языку Kotlin. Безусловно, Джеймс является личностью, колоссальным образом повлиявшей на индустрию и внёсшей огромный вклад. Его присутствие в числе спикеров большая удача для конференции.



В перерыве между большими докладами можно было посмотреть познавательные интервью, одним из которых стало ML и AI: Как сейчас выглядит разработка решений в крупных компаниях Андрея Дмитриева с Дмитрием Бугайченко про машинное обучение и искусственный интеллект. Достаточно интересно было послушать мнение Дмитрия, являющегося экспертом в этой области и докладчиком этой и других конференций JUG Ru Group.



Доклад Precomputed data access with Micronaut Data от Graeme Rocher, автора Micronaut Framework. У данного спикера на конференции два доклада (доклад Micronaut deep dive был в этот же день чуть раньше, его я ещё планирую посмотреть). Очень полезным оказалось предварительное ознакомление с интервью, взятым недавно. В данном докладе было рассказано про Micronaut Data, легковесное решение для доступа к базам данных, выглядящее чрезвычайно привлекательно. После доклада Грэму вопросы слушателей и свои задавал Антон Архипов. На интересующий многих заданный Антоном вопрос, возможно ли использование Micronaut Data без всего остального из Micronaut Framework, был дан положительный ответ.



Второй день


В нативный код из уютного мира Java: Путешествие туда и обратно блестящий доклад Ивана Углянского на тему возможностей вызова из Java-кода процедур и функций нативных (native) библиотек. Всеобъемлющая ретроспектива существовавших до JNI альтернатив (JDK 1.0 NMI, RNI, JRI), популярных существующих сейчас (JNA, JNR, JavaCPP) и перспективных пока что экспериментальных (Panama, Sulong). Подробное сравнение всего современного вышеперечисленного (начиная с JNI) с большим количеством слайдов говорит об огромной проделанной работе. Очень удачные выбранные аналогии на тему произведений Толкиена: левый слайд (Шир) иллюстрирует милый и безопасный Java-код, правый слайд опасный нативный код (Мордор).



How to develop a successful Kubernetes native application using Quarkus небольшой пятнадцатиминутный доклад Alex Soto Bueno от компании RedHat, спонсора конференции. Доклад о разработке микросервисов с использованием Kubernetes и фреймворка Quarkus, детища RedHat.



Олег Шелаев является одним из тех спикеров, доклады которых всегда можно смело выбирать, зная, что совершенно точно будет интересно, увлекательно и полезно. Обладает редкой способностью просто объяснять очень сложные с технической точки зрения вещи. Доклад под названием Polyglot done right with GraalVM не стал исключением в этом смысле. В нём Олег продолжил раскрывать тему GraalVM, являясь developer advocate проекта GraalVM в OracleLabs. В данном докладе более полно была раскрыта направленность продукта на возможность одновременного применения различных языков программирования: API, шаблоны взаимодействия и прочие детали GraalVM. Ожидания от прослушанного полностью оправдались, отличный доклад.



Третий день


Всеволод Брекелов входит в команду JUG Ru Group, активно участвуя в проведении летнего блока конференций, к которому относится и конференция JPoint. Тем интереснее, регулярно видя его в роли ведущего конференций, было посмотреть доклад в его исполнении под названием Contract testing: Should or shouldn't? Ему очень удачно помогали Андрей Дмитриев, Владимир Плизга и Алексей Виноградов например, представление Владимиром докладчика в самом начале просто восхищает оригинальностью. Обсуждение было посвящено контрактным тестам, были последовательно продемонстрированы несколько подходов с использованием Spring Cloud Contract, Pact и Protocol Buffers. Получилось зажигательно и интересно.



Доклад Страх и ненависть в Scala и Kotlin interop от Маргариты Недзельской был посвящён проблемам взаимодействия кода, написанного на двух JVM-языках Kotlin и Scala. Название доклада является аллюзией на фильм Fear and Loathing in Las Vegas, им же достаточно оригинально был проиллюстрирован весь рассказ. Проблемы вызвали искреннее сочувствие, технические подробности были приведены весьма убедительные. Маргарите помогали Паша Финкельштейн и Евгений Мандриков, ведя беседу, озвучивая результаты голосований и задавая вопросы слушателей.



Четвёртый день


Ещё немного маленьких оптимизаций стал своеобразным продолжением доклада, сделанным на конференции Joker 2019 тем же автором, Тагиром Валеевым. Доклад первой части был посвящён улучшениям в строках, коллекциях и операциям с числами, в этот раз уже другим оптимизациям тоже в строках, коллекциях и теперь ещё и в reflection. Изменения, о которых было рассказано, произошли в версиях Java с 9 по 16. Традиционное глубокое понимание темы, множество результатов сравнений, характерные для докладов Тагира всё это было и в этот раз.



На Интервью и Q&A с Алексеем Шипилёвым интервьюеры Алексей Фёдоров и Иван Крылов поговорили и задали вопросы Алексею Шипилёву об особенностях работы в Red Hat, про используемые инструменты performance-инженера, про различия сборщиков мусора в Java, историю создания Shenandoah GC, об отношении к статьям с замерами производительности, мнении о GraalVM, про совместное использование jmh и async-profiler, о советах для молодых разработчиков и инженеров.



Пятый день


Совместный доклад настоящих звёзд конференций Баруха Садогурского и Евгения Борисова, озаглавленный ими Вырасти своего работодателя в условиях коронавируса, Или как сделать так, чтобы вас не уволили в кризис об особенностях удалённой работы, типах руководителей, проблемах при человеческих коммуникациях с рекомендациями для решения всех возникающих при этом проблем. Хороший нетехнический доклад в завершающий день конференции, демонстрация помех для работы при участии семьи Евгения Борисова в конце доклада была просто великолепна.



Внедрение open source-решений на примере Одноклассников: интервью Дмитрия Чуйко с Андреем Паньгиным. Одной из тем разговора стал переход компанией Одноклассники на использование дистрибутива Liberica JDK компании BellSoft, поэтому представляющий BellSoft Дмитрий Чуйко в качестве берущего интервью был весьма уместен. Также были упомянуты популярные проекты Андрея one-nio и async-profile, тоже являющиеся open source-решениями и вызывающие интерес и уважение.



Доклад Valhalla is coming от Сергея Куксенко был продолжение его же предыдущего доклада, сделанного им на Joker 2019. С конца октября 2019 года в разработке инлайн-типов произошли значительные изменения, подробно о которых было рассказано примерно с середины данного доклада. Сергей харизматичный спикер и высококвалифицированный инженер, доклады которого безошибочно всегда можно выбирать. Отлично дополнил доклад Иван Углянский, задававший вопросы и помогавший Сергею во взаимодействии со слушателями.



Прочие события


Кроме впечатляющей онлайн-платформы для стриминга конференций, всевозможных активностей во время их проведения к летним конференциям была выпущена новая версия веб-приложения, о котором ранее уже писалось в обзорах про конференции TechTrain 2019 и Joker 2019. Приложение доступно по ссылке, в репозитории на GitHub (ставьте звёздочки) имеется описание с информацией, включающей актуальную ссылку на веб-сайт.

Приложение, ранее бывшее только игрой по угадыванию спикера, теперь разделено на две части. В первой из них можно произвести поиск и просмотр информации обо всех конференциях JUG Ru Group, а также митапах Java-сообществ JUG.ru, JUG.MSK, JUGNsk. Содержится абсолютно та же информация, что и представленная на сайтах конференций и митапов. Доступны для удобного просмотра уже опубликованные видео и презентации докладов (ниже для примера показано отображение сведений об Антоне Архипове и об одном из его докладов).



В разделе со статистикой приведены сведения, которые могут заинтересовать как организаторов конференций, так и их участников: с какого времени проводится каждая из конференций или каждый из митапов, общая их длительность, количество конференций, докладов и спикеров, сколько из спикеров удостоено звания Java Champion или Most Valuable Professional (MVP). Можно щёлкнуть по картинкам для их увеличения (или посмотреть то же самостоятельно в веб-приложении по ссылке, приведённой выше).

Второй и третий скриншоты ниже показывают топ спикеров по количеству сделанных ими докладов (скриншот слева без учёта митапов, справа конференции вместе с митапами). Уверенную победу в обоих случаях (только конференции и конференции с митапами) одерживает Барух Садогурский, на втором месте Евгений Борисов. Третье месте в случае только конференций Кирилл Толкачёв, конференции с митапами Алексей Шипилёв.



В игре Угадай спикера, второй части веб-приложения, после загрузки данных обо всех конференциях и митапах стало возможным использовать все ранее доступные режимы угадывания для конкретной конференции (например, JPoint 2020). По умолчанию для угадывания предлагается в данный момент идущая либо ближайшая конференция. Дополнительно были реализованы возможности попытаться угадать Twitter, GitHub спикеров и, наоборот, спикера по представленному их Twitter, GitHub.



Закрытие


Процедура закрытия, сопровождавшаяся ранее полным зрителей залом и традиционным выходом на сцену спикеров, участников программного комитета и организаторов, в связи с онлайн-форматом претерпела существенные изменения. Кроме закрывающих конференцию Всеволода Брекелова и Алексея Фёдорова на экране можно было увидеть в прямом эфире многих организаторов и спикеров.



Совершенно точно, что в сложившейся сегодня ситуации команда JUG Ru Group сделала абсолютно всё возможное (мне кажется, что даже чуточку больше), чтобы праздник, которым конференция всегда бывает и для спикеров, и для обычных участников, состоялся. В какой-то степени, праздник можно продлить у каждого осталось много замечательных докладов, оставшихся пока непросмотренными, и имеется возможность поделиться своими впечатлениями от конференции в комментариях к статье.

Сезон летних конференций JUG Ru Group продолжается по-прежнему можно успеть присоединиться к оставшимся двум онлайн-конференциям DevOops (6-10 июля 2020 года) и Hydra (6-9 июля 2020 года). Есть возможность купить единый билет на все восемь конференций, видео докладов в этом случае становятся доступны сразу же после завершения конференций.
Подробнее..

Перевод Простое ускорение Java с помощью Quarkus и JHipster

01.06.2021 20:15:10 | Автор: admin

К старту курса о разработке на Java делимся переводом вводной статьи о Quarkus "родной" для Kubernetes Java-платформе для создания высокопроизводительных веб-, бессерверных (serverless) и нативных приложений (оптимизированных для используемых микропроцессоров). В ней используются предварительная компиляция AOT и агрессивная оптимизация, например сканирование путей к классам, перезагрузка конфигурации и предварительная конфигурация самозагрузки приложения в процессе сборки. Результатом становится впечатляющая скорость загрузки. Другими словами, приложения, созданные с Quarkus, запускаются не просто быстро, а очень быстро!


Так же как для платформ Spring и Micronaut, в Quarkus можно использовать преимущество GraalVM для преобразования JVM-приложений в нативные исполняемые файлы, что ещё больше повышает их быстродействие.

Такой прирост производительности позволяет этой Java-платформе конкурировать с бессерверными, облачными и созданными на основе Kubernetes средами, создавая приложения Supersonic Subatomic Java. В Quarkus используются стандарты Java (такие, как MicroProfile, JAX-RS), а также лучшие из существующих Java-библиотек (например, Hibernate и Vert.x). Есть даже поддержка аннотаций Spring.

Quarkus + JHipster = простое ускорение Java

История технологий разработки наглядно демонстрирует, что совместить различные компоненты бывает очень непросто. Разработчики любят, когда им предлагается что-то авторитетно-одобренное, и как раз здесь на сцену выходит JHipster.

JHipster это сопровождаемая сообществом разработчиков полнофункциональная платформа разработки, позволяющая создавать, развивать и развёртывать веб-приложения и ориентированные на микросервисы архитектуры. Стандартной серверной платформой в JHipster является Spring Boot, но постоянно появляются всё новые и новые возможности. Одним из таких вариантов стала blueprint-схема JHipster Quarkus.

Помимо прочего, одной из ключевых возможностей, определяющих успех JHipster, стала его расширяемость с помощью blueprint-схем. Blueprint-схема действует как плагин JHipster и позволяет вам переопределять стандартное поведение, настраивая его на свой вкус.

Например, blueprint-схема Kotlin с JHipster является популярным дополнением, которое любят использовать разработчики. Использование blueprint-схемам многократно расширяет границы возможностей. Вот почему в JHipster есть даже реализации без Java (такие, как Node + NestJS и .NET Core). Эта публикация познакомит вас с основными шагами по использованию JHipster, blueprint-схемой Quarkus, а также протоколом OAuth для создания оптимизированного для работы на конкретных микропроцессорах и безопасного полнофункционального приложения.

Создание Java-приложения с Quarkus

Прежде чем приступить к работе, необходимо установить несколько инструментов.

Предварительные требования:

Установите JHipster и его blueprint-схему Quarkus, используя npm:

# Install JHipster globallynpm install -g generator-jhipster@6.10.5# Install the JHipster Quarkus blueprintnpm install -g generator-jhipster-quarkus@1.1.1

Команда jhipster-quarkus сокращение для jhipster --blueprints quarkus. Посмотреть все варианты её синтаксиса можно с помощью команды --help.

$ jhipster-quarkus --help

Создание приложения в среде JHipster Quarkus

mkdir okta-jhipster-quarkus-example && cd okta-jhipster-quarkus-example# oh-my-zsh users: take okta-jhipster-quarkus-example

Чтобы запустить мастер создания приложений, можно выполнить команду jhipster-quarkus:

jhipster-quarkus

В этой вводной статье основным вопросом будет выполнение аутентификации.

Среда JHipster Quarkus позволяет использовать JWT (с возможностью управления пользователями в базе данных приложений) или аутентификацию OAuth 2.0/OIDC с применением поставщиков идентификационной информации, таких как Keycloak и Okta. OIDC расшифровывается как OpenID Connect, этот протокол представляет собой тонкий слой поверх протокола аутентификации OAuth 2.0. Его основная задача обеспечить аутентификацию и идентификацию пользователя.

Ниже представлен пример ответов на вопросы мастера создания приложений.

После того как вы ответите на все эти вопросы, JHipster создаст код вашего приложения и выполнит команду npm install.

{  "generator-jhipster": {    "promptValues": {      "packageName": "com.mycompany.myapp",      "nativeLanguage": "en"    },    "jhipsterVersion": "6.10.5",    "applicationType": "monolith",    "baseName": "jhipster",    "packageName": "com.mycompany.myapp",    "packageFolder": "com/mycompany/myapp",    "serverPort": "8080",    "authenticationType": "oauth2",    "cacheProvider": "no",    "enableHibernateCache": true,    "websocket": false,    "databaseType": "sql",    "devDatabaseType": "h2Disk",    "prodDatabaseType": "mysql",    "messageBroker": false,    "buildTool": "maven",    "embeddableLaunchScript": false,    "useSass": true,    "clientPackageManager": "npm",    "clientFramework": "angularX",    "clientTheme": "none",    "clientThemeVariant": "",    "creationTimestamp": 1614834465776,    "jhiPrefix": "jhi",    "entitySuffix": "",    "dtoSuffix": "DTO",    "otherModules": [      {        "name": "generator-jhipster-quarkus",        "version": "1.1.1"      }    ],    "enableTranslation": true,    "nativeLanguage": "en",    "languages": ["en"],    "blueprints": [      {        "name": "generator-jhipster-quarkus",        "version": "1.1.1"      }    ]  }}

В этом файле содержатся все ответы на исходные вопросы мастера JHipster, что позволит создать приложение без дополнительных запросов.

Убедитесь, что выполняемая с помощью Keycloak аутентификация OAuth 2.0/OIDC действительно работает

Помимо прочих файлов JHipster Quarkus создаёт файлы для инструментального средства Docker Compose, помогающие загрузить среду разработки, настроенную для вашего только что созданного приложения. При этом даже выполняется импорт данных Keycloak, заданных по умолчанию для пользователей и приложений, и вам не придётся делать это самим.

https://gitlab.webant.ru/russia_quiz/frontend/-/merge_requests

Если Keycloak запущен и работает, вы сможете выполнить вход в систему. Запустите ваше приложение с помощью Maven:

./mvnw

Вы можете видеть, что приложение запускается за 3,351 с, также выводится обширный список расширений Quarkus (включая oidc). Перейдите по адресу http://localhost:8080 в предпочитаемом вами браузере и нажмите ссылку sign in (вход).

Вы будете перенаправлены в Keycloak для входа в систему. При запросе идентификационных данных введите admin/admin.

После успешного прохождения аутентификации вы будете перенаправлены обратно в ваше приложение Quarkus.

Как работает поддержка протокола аутентификации OAuth 2.0 в JHipster Quarkus

Одной из проблем при разработке blueprint-схем JHipster, таких как Quarkus, является необходимость найти правильный баланс между повторным использованием существующих механизмов и добавлением индивидуальных реализаций.

С самого первого дня своего появления JHipster осуществлял интеграцию всех современных платформ для создания веб-приложений (Angular, React или даже Vue.js), совмещая их с фактически стандартными Java-технологиями, такими как Spring Boot и Spring Cloud.

В реализации JHipster Quarkus OAuth 2.0 за основу взято URI-перенаправление login/oauth2/code/oidc, предполагающее использование платформы аутентификации Spring Security. Настоятельно рекомендуем выполнять аутентификации на стороне сервера, поскольку это намного безопаснее (так как у браузера нет необходимости управлять какими-либо идентификационными данными и хранить какие-либо маркеры доступа).

В среде JHipster Quarkus, чтобы повторно использовать без изменений клиентские приложения и реализовать на серверной стороне механизм аутентификации по протоколу OAuth 2.0, в бэкенде должны быть открыты два HTTP-маршрута. Вот почему в JHipster Quarkus предусмотрен контроллер UserOauth2Controller и настраиваемые свойства Quarkus OIDC, позволяющие обеспечить правильную работу всего механизма.

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

Объединение JHipster Quarkus с сервисом Okta

Из этого раздела вы узнаете, как использовать сервис Okta в качестве провайдера протокола аутентификации OAuth 2.0/OIDC. В Okta предусмотрены два варианта для конфигурирования OIDC-приложения. Это можно выполнить либо в консоли разработчика, либо с помощью инфраструктуры Okta CLI.

Использование инфраструктуры Okta CLI для конфигурирования JHipster

Инфраструктура Okta CLI автоматизирует для вас все конфигурации JHipster и Okta. Для установки Okta CLI можно воспользоваться популярными менеджерами пакетов.

macOS (с помощью Homebrew):

brew install --cask oktadeveloper/tap/okta

Linux (с помощью Flatpak):

# Add Flathub repoflatpak remote-add --if-not-exists flathub https://flathub.org/repo/flathub.flatpakrepo# install the packageflatpak install com.okta.developer.CLI# add this to your appropriate dot filealias okta="flatpak run com.okta.developer.CLI"

Windows (с помощью Chocolatey):

choco install okta -version 0.8.0

Вы также можете просто передать его в оболочку bash:

curl https://raw.githubusercontent.com/okta/okta-cli/master/cli/src/main/scripts/install.sh | bash

Если у вас ещё нет аккаунта разработчика в Okta, откройте терминал, перейдите в каталог приложения Quarkus и выполните okta register. Если у вас есть аккаунт, выполните okta login.

$ okta registerFirst name: DanielLast name: PetismeEmail address: daniel.petisme@gmail.comCompany: OktaCreating new Okta Organization, this may take a minute:OrgUrl: https://dev-9323263.okta.comAn email has been sent to you with a verification code.Check your emailVerification code: 232819New Okta Account created!Your Okta Domain: https://dev-9323263.okta.comTo set your password open this link:https://dev-9323263.okta.com/welcome/drpt2SjbRAPR-gvVHhnm

Если у вас уже есть аккаунт разработчика Okta, выполните команду okta login. Затем из каталога приложения Quarkus выполните okta apps create jhipster. Примите предлагаемые по умолчанию предложения для перенаправления URI.

$ okta apps create jhipsterApplication name [okta-jhipster-quarkus-example]:Redirect URICommon defaults:  Spring Security - http://localhost:8080/login/oauth2/code/okta  Quarkus OIDC - http://localhost:8080/callback  JHipster - http://localhost:8080/login/oauth2/code/oidcEnter your Redirect URI(s) [http://localhost:8080/login/oauth2/code/oidc, http://localhost:8761/login/oauth2/code/oidc]:Enter your Post Logout Redirect URI(s) [http://localhost:8080/, http://localhost:8761/]:Configuring a new OIDC Application, almost done:Created OIDC application, client-id: 0oa5ozjxyNQPPbKc65d6Creating Authorization Server claim 'groups':Adding user daniel.petisme@gmail.com to groups: [ROLE_USER, ROLE_ADMIN]Creating group: ROLE_USERCreating group: ROLE_ADMIN

Конфигурация приложения Okta записывается здесь: /Users/daniel/workspace/okta-jhipster-quarkus-example/.okta.env

ПРИМЕЧАНИЕ: идентификаторы URI, перенаправленные http://localhost:8761*, предназначены для реестра JHipster, который часто используется при создании микросервисов с помощью JHipster. В инфраструктуре Okta CLI они добавляются по умолчанию. Они не требуются для приложения, создаваемого в этой вводной статье, но если их оставить, то никакого вреда точно не будет.

Инфраструктура Okta CLI создаст файл .okta.env в текущем каталоге. Если посмотреть на него, то вы увидите, что в нём содержатся несколько ключей и значений, предназначенных для протокола OIDC.

$ cat .okta.envexport QUARKUS_OIDC_AUTH_SERVER_URL="http://personeltest.ru/aways/dev-9323263.okta.com/oauth2/default"export QUARKUS_OIDC_CLIENT_ID="0oa5ozjxyNQPPbKc65d6"export QUARKUS_OIDC_CREDENTIALS_SECRET="KEJ0oNOTFEUEFHP7i1TELLING1xLm1XPRn"export QUARKUS_OIDC_AUTHENTICATION_REDIRECT_PATH="/login/oauth2/code/oidc"export JHIPSTER_OIDC_LOGOUT_URL="http://personeltest.ru/aways/dev-9323263.okta.com/oauth2/default/v1/logout"

Установите файл, чтобы задать переменные среды, и запустите ваше приложение с помощью Maven.

source .okta.env./mvnw

Обязательно добавьте \*.env в ваш файл .gitignore, чтобы в коммиты не попадал ваш секрет клиента.

Как только приложение будет запущено, в окне в режиме инкогнито откройте http://localhost:8080 и выполните вход. Вам будет предложено ввести свои идентификационные данные Okta.

После успешного прохождения аутентификации вы будете перенаправлены обратно в ваше приложение. На начальной странице должен отображаться ваш адрес электронной почты.

Инфраструктура Okta CLI упрощает конфигурирование JHipster и выполняет следующие полезные операции.

  1. Создаётся приложение OIDC с правильным перенаправлением URI.

  2. Заводятся группы ROLE_ADMIN и ROLE_USER, требуемые для JHipster.

  3. Ваш текущий пользователь добавляется в группы ROLE_ADMIN и ROLE_USER.

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

Но вдруг вы не любите работать из командной строки? Не паникуйте, тут есть кому прикрыть вашу спину! Инфраструктура Okta CLI проста в использовании, но для тех, кому это необходимо, есть возможность выполнить настройки с помощью интерфейса пользователя. Именно поэтому я так подробно рассматриваю каждый шаг по настройке приложения OIDC, работающего с JHipster Quarkus.

Использование консоли разработчика Okta для настройки JHipster

Если у вас нет аккаунта разработчика Okta, необходимо нажать ссылку sign up (вход). Тут нет ничего сверхсложного: просто укажите имя, фамилию, адрес электронной почты, выберите надёжный пароль и всё вы готовы двигаться дальше. Выполнив вход в систему, вы попадаете в консоль разработчика:

Разверните вложенное меню Applications (Приложения) на панели навигации слева, затем выберите в меню Applications > Create App Integration (Приложения > Создать интеграцию приложений), чтобы запустить мастер создания приложений.

Выберите OIDC и Web Application. Затем нажмите кнопку Next (Далее).

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

  • Name (Имя): можете указать любое имя на свой вкус, но разве JHipster Quarkus чем-то не подходит?

  • Login redirect URIs (Перенаправление URI при входе): определяет, будет ли Okta выполнять перенаправление в браузере клиента после аутентификации. Установите для него http://localhost:8080/login/oauth2/code/oidc, именно это значение настроено по умолчанию.

  • Logout redirect URIs (Перенаправление URI при выходе): http://localhost:8080 указывается, куда будет перенаправляться пользователь после выполнения выхода.

  • Group assignments (Назначения групп): определяет, какие группы могут использовать это приложение.

Используйте предлагаемые значения по умолчанию для всех остальных настроек. Завершив ввод требуемых настроек для своего приложения, нажмите Save (Сохранить). На экране отобразятся подробные сведения о вашем приложении.

Наиболее важными являются следующие значения:

  • идентификационные данные клиента (ID и секрет клиента). Они позволяют приложению Java выполнять аутентификацию в сервисах Okta для последующей обработки потоков аутентификации и авторизации пользователей;

  • домен Okta, из которого Quarkus будет выводить конечные точки адресов URL для протоколов OAuth/OIDC.

Создание групп пользователей

Теперь настало время для создания групп пользователей. По умолчанию для JHipster требуются две следующие группы:

  • ROLE_USER: для аутентифицированных пользователей;

  • ROLE_ADMIN: для аутентифицированных пользователей с административными правами для этого приложения.

В консоли разработчика выберите в меню Directory > Groups (Каталог > Группы). Нажмите Add Group (Добавить группу) и создайте группу ROLE_ADMIN

Теперь добавьте группу ROLE_USER.

Всё, вы завершили создание групп, теперь займёмся добавлением пользователей.

Создание пользователей

Чтобы увидеть различие между обычными и административным пользователями, создайте пользователей в каждой из групп. Используя консоль разработчика Okta, выберите в меню Directory > People (Каталог > Люди). Нажмите Add Person (Добавить человека). Начните с создания пользователя Administrator.

Основным моментом тут является привязка пользователя Administrator к группе ROLE_ADMIN. Чтобы определить исходный пароль, который пользователь должен будет изменить, исключительно в демонстрационных целях для данной вводной статьи использована стратегию выбора пароля Set by Admin (Задаётся администратором). В реальном проекте я рекомендую использовать стратегию Set by User (Задаётся пользователем) с активацией по электронной почте. Теперь добавим обычного пользователя.

Убедитесь, что пользователь User входит в группу ROLE_USER. Очень важно использовать действующий адрес электронной почты, так как он может понадобиться при восстановлении пароля. Выберите в меню Applications > JHipster Quarkus (Приложения > JHipster Quarkus) и нажмите Assignments (Назначения). Назначьте группам пользователей, которых только что создали.

Добавление заявки на группы к маркеру ID

Последнее, о чём необходимо вам позаботиться, это настроить заявку на группы, включающую группы пользователей в маркер ID. Выберите в меню Security > API (Безопасность > API), а затем нажмите default (по умолчанию). Щёлкните Claims > Add Claim (Заявки > Добавить заявку). Введите следующие значения:

  • Name (Имя): groups (группы);

  • Include in token type (Включить тип маркера): ID Token (Маркер ID);

  • Value type (Тип значения): groups (группы);

  • Filter (Фильтр): Matches regex with a value of .* (Соответствует регулярному выражению со значением .*).

Нажмите Create (Создать). Конфигурация Okta для JHipster готова!

Настройка Quarkus OIDC для Okta

В этот момент необходимо, чтобы приложение JHipster Quarkus уже было запущено и для использования Keycloak в качестве провайдера идентификационных данных для него. Давайте изменим настройки для работы с Okta. Во-первых, необходимо выйти из веб-приложения JHipster, чтобы предотвратить конфликт файлов cookie. Выберите Account > Sign Out (Аккаунт > Выход).

ПРИМЕЧАНИЕ: можно оставить приложение запущенным. Quarkus поддерживает работу в так называемом режиме для разработки (Dev Mode), обеспечивающем горячую перезагрузку любых исходных или ресурсных файлов при каждом их обновлении. Это исключительно удобно!

Откройте для редактирования файл src/main/resources/application.properties и найдите в нём раздел со следующей конфигурацией OIDC.

# OAuth 2.0 and OIDCquarkus.oidc.enabled=truequarkus.oidc.auth-server-url=http://localhost:9080/auth/realms/jhipster/%dev.quarkus.oidc.client-id=web_app%dev.quarkus.oidc.credentials.secret=web_appquarkus.oidc.application-type=hybridquarkus.oidc.authentication.scopes=profile,address,email,address,phone,offline_accessquarkus.oidc.authentication.cookie-path=/quarkus.oidc.authentication.redirect-path=/login/oauth2/code/oidcquarkus.oidc.authentication.restore-path-after-redirect=falsejhipster.oidc.logout-url=http://localhost:9080/auth/realms/jhipster/protocol/openid-connect/logout%test.quarkus.oidc.client-id=dummy%test.quarkus.oidc.application-type=service%test.jhipster.oidc.logout-url=some-dummy-logoutUrl

Показанные выше значения предназначены для Keycloak. Вами необходимо обновить следующие свойства, чтобы интегрировать своё приложение с Okta;

  • quarkus.oidc.auth-server-url: корневой URL для API Okta, полученный из домена приложения OIDC;

  • quarkus.oidc.client-id: ID клиента для приложения OIDC;

  • quarkus.oidc.credentials.secret: секрет клиента для приложения OIDC;

  • jhipster.oidc.logout-url: в JHipster браузер будет запускать выход из системы. Серверная сторона должна предоставлять эту информацию (пока её невозможно получить с помощью OIDC-поиска).

После того как вы обновите этот файл, ваши настройки должны выглядеть примерно так:

# OAuth 2.0 and OIDCquarkus.oidc.enabled=truequarkus.oidc.auth-server-url=https://dev-9323263.okta.com/oauth2/defaultquarkus.oidc.client-id=0oaajhdr9q9jxbBM95d6quarkus.oidc.credentials.secret=NEVERSHOWSECRETSquarkus.oidc.application-type=hybridquarkus.oidc.authentication.scopes=profile,address,email,address,phonequarkus.oidc.authentication.cookie-path=/quarkus.oidc.authentication.redirect-path=/login/oauth2/code/oidcquarkus.oidc.authentication.restore-path-after-redirect=falsejhipster.oidc.logout-url=https://dev-9323263.okta.com/oauth2/default/v1/logout

Перезапустите приложение, перейдите по адресу http://localhost:8080. Нажмите sign in (вход) и вы будете перенаправлены на страницу входа Okta.

Введите admin в качестве имени пользователя и пароль, который вы задали. Okta определит, что это ваш первый вход в систему, и предложит сменить пароль. После выполнения вы будете перенаправлены в ваше приложение Quarkus.

Переход в нативный формат с помощью Quarkus и GraalVM

Заключительным шагом в данной вводной статье будет упаковка приложения Java в виде нативного выполняемого файла (оптимизированного для используемого микропроцессора). И снова JHipster надёжно прикрывает ваши тылы, делая для вас всё необходимое. Просто выполните в Maven команду package с профилем native:

./mvnw package -Pnative -DskipTests

Вы знаете, мы знаем, все знают: мы пропустили этап тестирования в этом демонстрационном примере всё работает идеально. Но, пожалуйста, никогда не пропускайте тестирование в условиях реальной промышленной разработки.Если в используемый вами JDK не включён GraalVM, вы получите ошибку:

[error]: Build step io.quarkus.deployment.pkg.steps.NativeImageBuildStep#build threw an exception: java.lang.RuntimeException: Cannot find the `native-image` in the  GRAALVM_HOME, JAVA_HOME and System PATH. Install it using `gu install native-image`

Самым простым способом решения этой проблемы будет применение SDKMAN для установки Java 11 с GraalVM:

sdk install java 21.0.0.2.r11-grl

Затем выполните gu install native-image:

$ gu install native-imageDownloading: Component catalog from www.graalvm.orgProcessing Component: Native ImageDownloading: Component native-image: Native Image  from github.comInstalling new component: Native Image (org.graalvm.native-image, version 21.0.0.2)

Как только процесс завершится, перезапустите команду package в Maven:

./mvnw package -Pnative -DskipTests

На нативную компиляцию требуется немало времени. У вас может возникнуть желание прогуляться, выпить чашку-другую кофе или несколько раз отжаться. Но, если вы предпочитаете остаться за компьютером, можно потратить время на следующее:

  • ознакомиться с проектом JHipster Quarkus Blueprint;

  • исследовать сайт для разработчиков Okta;

  • изучить эти великолепные руководства по Quarkus.

Спустя примерно три минуты нативный выполняемый файл должен быть готов:

Запустите его как нативный выполняемый файл, используя команду target/*runner:

Ваше старое доброе Java-приложение запустится через 1 секунду! Помните, я рассказывал о приросте памяти? Ниже привожу команду, как посмотреть потребление памяти в мегабайтах:

$ ps -o pid,rss,command | grep --color jhipster | awk '{$2=int($2/1024)"M";}{ print;}'30951 46M ./target/jhipster-1.0.0-SNAPSHOT-runner31433 0M grep --color=auto --exclude-dir=.bzr --exclude-dir=CVS --exclude-dir=.git --exclude-dir=.hg --exclude-dir=.svn --color jhipster

Ваше приложение потребляет менее 50 МБ памяти. Перейдите по адресу http://localhost:8080 и убедитесь, что всё исправно работает. Теперь наслаждайтесь своим успехом!

Дальнейшая разработка с помощью JHipster Quarkus

Надеюсь, вы получили удовольствие от данной вводной статьи, пройдя все этапы создания нативного приложения и применяя для этого Java, Quarkus и JHipster. Не правда ли, впечатляет, как JHipster и Okta CLI делают для вас основную тяжёлую работу?! Вы можете найти пример, созданный в этой вводной статье, на GitHub. Если вы заинтересованы в дополнительном изучении blueprint-схем Quarkus, посмотрите проект generator-jhipster-quarkus, также размещённый на GitHub.

Совсем недавно Java считали медленным языком программирования, а вернее было бы сказать, что медленной была виртуальная машина Java, но это не помешало языку стать одним из самых востребованных по версии TIOBE. Сегодня Java становится всё быстрее, а это значит, что она ещё надолго сохранит способность конкурировать с новыми языками; кроме того, в последнее время наметилась тенденция к упрощению синтаксиса Java. Если вам интересен этот язык и работа с ним в перспективе, то вы можете посмотреть на программу обучения нашего курса по Java, где студенты за 14 месяцев получают всестороннюю подготовку к трудоустройству в качестве Java-разработчика.

Узнайте, как прокачаться и в других специальностях или освоить их с нуля:

Другие профессии и курсы
Подробнее..

Релиз Spring Native Beta

13.03.2021 20:20:43 | Автор: admin

Недавно команда, занимающаяся портированием Spring для GraalVM, выпустила первый крупный релиз - Spring Native Beta. Вместе с создателями GraalVM они смогли пофиксить множество багов как в самом компиляторе так и спринге. Теперь у проекта появилась официальная поддержка, свой цикл релизов и его можно щупать :)


Самым главным препятствием при переносе кода из JVM в бинарники является проблема использования фишек, присущих только java - рефлексия, работа с classpath, динамическая загрузка классов и т.д.

Согласно документации, ключевые различия между обычным JVM и нативной реализацией заключаются в следующем:

  • Статический анализ всего приложения выполняется во время сборки.

  • Неиспользуемые компоненты удаляются во время сборки.

  • Рефлексия, ресурсы и динамические прокси могут быть настроены только с помощью дополнительных конфигураций.

  • На время сборки фиксируются все компоненты в Classpath.

  • Нет ленивой загрузки класса: при загрузке все, что поставляется в исполняемых файлах, будет загружено в память. Например, чтобы вызов Class.forName ("myClass") отработал верно, нужно иметь myClass в файле конфигурации. Если в файле конфигурации не будет найден класс, который запрашивается для динамической загрузки класса, будет выбрано исключение ClassNotFoundException

  • Часть кода будет запущена во время сборки, чтобы правильно связать компоненты. Например, тесты.

В самом спринге рефлексия, создание прокси и ленивая инициализация встречается практически везде, поэтому все конфигурации надо было аккуратно обработать, из-за этого к релизу шли больше года.

В ходе исследований был создан новый компонент Spring AOT, который отвечает за все необходимые преобразования вашего кода в удобоваримый для Graal VM формат.

Spring AOT анализирует код и на основе него создает файлы конфигурации такие как native-image.properties, reflection-config.json, proxy-config.json или resource-config.json.

Так как Graal VM поддерживает первоначальную настройку через статические файлы, эти файлы помещаются при сборке в каталог META-INF/native-image.

Для каждого сборщика выпущен свой плагин, который активирует работу Spring AOT. Для maven это spring-aot-maven-plugin, соответственно для gradle - spring-aot-gradle-plugin.Для того, чтобы добавить gradle плагин в свой проект нужна всего одна строка:

plugins {id 'org.springframework.experimental.aot' version '0.9.0'}

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

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

Например, для случаев реализации компонентов с помощью WebClient можно использовать аннотацию из пакета org.springframework.nativex.hint, чтобы указать какой тип мы будем обрабатывать:

@TypeHint(types = Data.class, typeNames = "com.example.webclient.Data$SuperHero")@SpringBootApplicationpublic class WebClientApplication {// ...}

Здесь мы указываем, что будем сериализовать класс Data, в котором есть подкласс SuperHero. Во время сборки для нас заранее создадут клиент, который сможет работать с этим типом данных.

Так как graavlvm не поддерживает работу с динамическими прокси, то для поддержки работы с java.lang.reflect.Proxy создана аннотация @ProxyHint.

Применять ее можно, например, так:

@ProxyHint(types = {     org.hibernate.Session.class,     org.springframework.orm.jpa.EntityManagerProxy.class})

Если необходимо подтянуть какие-либо ресурсы в образ, то необходимо воспользоваться аннотацией@ResourceHint.Например, таким образом:

@ResourceHint(patterns = "com/mysql/cj/TlsSettings.properties")

Чтобы указать какие классы / пакеты должны быть инициализированы явно во время сборки или выполнения, нужно воспользоваться аннотацией @InitializationHint:

@InitializationHint(types = org.h2.util.Bits.class,    initTime = InitializationTime.BUILD)

Для того, чтобы компактно собрать все эти аннотации воедино создана аннотация @NativeHint:

@Repeatable(NativeHints.class)@Retention(RetentionPolicy.RUNTIME)public @interface NativeHint

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

@NativeHint(    trigger = Driver.class,    options = "--enable-all-security-services",    types = @TypeHint(types = {       FailoverConnectionUrl.class,       FailoverDnsSrvConnectionUrl.class,       // ...    }), resources = {@ResourceHint(patterns = "com/mysql/cj/TlsSettings.properties"),@ResourceHint(patterns = "com.mysql.cj.LocalizedErrorMessages",                      isBundle = true)})

В качестве тригера, мы выбираем тот класс, присутствие которого в classpath должно вызвать построение конфигурации.

Все активные аннотации учитываются во время компиляции и преобразуются в конфигурацию Graal VM плагином Spring AOT.

Spring Native уже включена в релизный цикл, забрать шаблон можно прямо со start.spring.io. Так как поддержка JPA и прочих spring компонентов уже реализована, то собрать простое CRUD приложение можно сразу. Если необходимо указать дополнительные параметры Graal VM при сборке, их можно добавить с помощью переменной среды BP_NATIVE_IMAGE_BUILD_ARGUMENTS в плагине Spring AOT, если сборка идет через Buildpacks, или с помощью элемента конфигурации <buildArgs> в pom.xml, если вы собираете через плагин native-image-maven-plugin.

Собственно, выполняем команды mvn spring-boot: build-image или gradle bootBuildImage - и начнется сборка образа. Стоит отметить, что сборщику нужно более 7 Гб памяти, для того сборка завершилась успешно. На моей машине сборка, вместе с загрузкой образов заняла не более 5 минут. При этом образ получился очень компактным, всего 60 Мб. Стартовало приложение за 0.022 секунды! Это невероятный результат. Учитывая, что все большее количество компаний переходит на K8s и старт приложения, так же как и используемые ресурсы очень важны в современном мире, то данная технология позволяет Spring сделать фреймворком номер один для всех типов микросервисов, даже для реализаций FaaS, где очень важна скорость холодного старта.

Подробнее..
Категории: Микросервисы , Java , Spring , Graalvm , Jvm , Graal

Из песочницы Удав укрощает Graal VM

04.11.2020 22:14:20 | Автор: admin


В мире Java за последнее время произошло много интересных событий. Одним из таких событий стал выход первой production ready версии Graal VM.


Лично у меня Graal давно вызывает нескрываемый интерес и я пристально слежу за докладами и последними новостями в этой области. Одно время попался на глаза доклад Криса Талингера. В нём Крис рассказывает как в Twitter удалось получить значительный выигрыш в производительности, применив для настройки Graal алгоритмы машинного обучения. У меня появилось стойкое желание попробовать подобное самому. В этой статье хочу поделится тем, что в итоге получилось.


Эксперимент


Для реализации эксперимента мне понадобились:


  1. cвежий Graal VM Community Edition. На момент написания статьи это 20.2.0
  2. выделенное облачное окружение для нагрузочного тестирования
  3. NewRelic для сбора метрик
  4. генератор тестовой нагрузки
  5. программа на Python и набор скриптов, для реализации самого алгоритма ML

Если описать задачу сухим языком математики, то она будет выглядеть так


Найти такие значения параметров $inline$A = (a_1,a_2,..,a_n)$inline$ при которых функция
$inline$f(x_1,x_2,..,x_n)$inline$ принимает максимальное значение.


Я решил минимизировать потребление процессорного времени и выбрал такую целевую функцию:


$$display$$f=1/mean(CPUUtilization)$$display$$


Чем меньше нагружен процессор, тем ближе целевая функция к единице.
В качестве параметров которые нужно найти взял те же, что и в докладе:


-Dgraal.MaximumInliningSize -Dgraal.TrivialInliningSize  -Dgraal.SmallCompiledLowLevelGraphSize

Все они отвечают за инлайнинг. Это важная оптимизация, которая позволяет
сэкономить на вызове методов.


С постановкой задачи оптимизации разобрались. Теперь пришло время пройтись по шагам
алгоритма оптимизации:


  1. алгоритм делает предположение о том какие параметры оптимальные
  2. меняет конфигурацию JVM и запускает нагрузочный тест
  3. снимает метрики и вычисляет значение целевой функции
  4. делает новое предположение на основе значения целевой функции

Процесс повторяется несколько раз.



В качестве алгоритма поиска Twitter предлагает использовать байесовскую оптимизацию. Она лучше справляется с зашумленными функциями и не требует большого количества итераций.


Байесовская оптимизация работает путем построения апостериорного распределения функций,
которое наилучшим образом её описывает. По мере роста количества наблюдений улучшается апостериорное распределение и алгоритм становится более определённым в том, какие регионы в пространстве параметров стоит изучить.


Получение метрик из NewRelic


Для работы с NewRelic REST API необходимо узнать свои APP_ID и API_KEY.
APP_ID это уникальный идентификатор приложения в системе. Его можно найти в разделе APM.
API_KEY необходимо создать или узнать из настроек профиля в NewRelic.


Структура ответа для всех метрик приблизительно одинакова и имеет следующий вид:


{  "metric_data": {    "from": "time",    "to": "time",    "metrics_not_found": "string",    "metrics_found": "string",    "metrics": [      {        "name": "string",        "timeslices": [          {            "from": "time",            "to": "time",            "values": "hash"          }        ]      }    ]  }}

В итоге метод для получения метрик будет таким:


def request_metrics(params):    app_id = "APP_ID"    url = "https://api.newrelic.com/v2/applications/"+ app_id + "/metrics/data.json"    headers = {'X-Api-Key':"API_KEY"}    response = requests.get(url, headers=headers, params=params)    return response.json()

Для получения CPU Utilzation значение params следующее:


params = {    'names[]': "CPU/User/Utilization",    'values[]': "percent",    'from': timerange[0],    'to': timerange[1],    'raw': "false"}

timerange хранит значения времени начала и конца нагрузочного теста.


Далее парсим запрос и извлекаем необходимые метрики


def get_timeslices(response_json, value_name):    metrics = response_json['metric_data']['metrics'][0]    timeslices = metrics['timeslices']    values = []    for t in timeslices:        values.append(t['values'][value_name])    return values

Алгоритм оптимизации


Перейдем к самому интересному поиску оптимальных параметров.


Для реализации байесовской оптимизации взял уже готовую библиотеку BayesianOptimization.


Сначала создадим метод для вычисления целевой функции.


def objective_function(maximumInliningSize, trivialInliningSize, smallCompiledLowLevelGraphSize):    update_config(int(maximumInliningSize), int(trivialInliningSize), int(smallCompiledLowLevelGraphSize))    timerange = do_test()    data = get_results(timerange)    return calculate(data)

Метод _updateconfig вызывает скрипт, который обновляет конфиг приложения. Далее в _dotest происходит вызов скрипта для запуска нагрузочного теста.


Каждое изменение конфигурации требует перезапуска JVM и первые несколько минут идёт фаза прогрева. Эту фазу необходимо отфильтровать, откинув первые минуты.


В методе calculate вычисляем целевую функцию:


    value = 1 / (mean(filtered_data))

Необходимо ограничить поиск


pbounds = {            'maximumInliningSize': (200, 500),           'trivialInliningSize': (10, 25),           'smallCompiledLowLevelGraphSize': (200, 650)           }

Так как улучшение должно быть относительно настроек по умолчанию, то я добавил соответствующую точку


  optimizer.probe(        params={"maximumInliningSize": 300.0,                "trivialInliningSize": 10.0,                "smallCompiledLowLevelGraphSize": 300.0},        lazy=True,        )

Окончательный метод ниже


def autotune():    pbounds = {                'maximumInliningSize': (200, 500),               'trivialInliningSize': (10, 25),               'smallCompiledLowLevelGraphSize': (200, 650)               }    optimizer = BayesianOptimization(        f=objective_function,        pbounds=pbounds,        random_state=1,    )    optimizer.probe(    params={"maximumInliningSize": 300.0,            "trivialInliningSize": 10.0,            "smallCompiledLowLevelGraphSize": 300.0},    lazy=True,    )    optimizer.maximize(        init_points=2,        n_iter=10,    )    print(optimizer.max)

В данном примере _objectivefunction выполнится 12 раз и в конце выведет значение
параметров, при которых наша целевая функция была максимальная. Чем больше итераций, то тем точнее мы приближаемся к максимуму функции.


При необходимости все итерации можно вывести вот так:


for i, res in enumerate(optimizer.res):    print("Iteration {}: \n\t{}".format(i, res))

Код выведет значения целевой функции и параметров для каждой итерации.


Iteration 0:    {'target': 0.02612330198537095, 'params': {'maximumInliningSize': 300.0, 'smallCompiledLowLevelGraphSize': 300.0, 'trivialInliningSize': 10.0}}Iteration 1:    {'target': 0.02666666666666667, 'params': {'maximumInliningSize': 325.1066014107722, 'smallCompiledLowLevelGraphSize': 524.1460220489712, 'trivialInliningSize': 10.001715622260173}}...

Результаты


Сравнил два прогона нагрузочного теста с настройками по умолчанию и вычисленными в ходе эксперимента.


На графике можно заметить, что CPU Utilization уменьшился для случая Graal



Среднее время отклика также незначительно снизилось:



Пропускная способность ограничена сверху и никак не менялась для обоих прогонов.



Заключение


В итоге удалось получить снижение нагрузки CPU в среднем на 4-5%.


Для нашего проекта такая экономия на CPU не существенна, но для proof of concept
результат достаточно неплохой.


С2 много лет оптимизировали под Java и поэтому соревноваться Graal с С2 пока сложно. Больше выгоды можно получить от связки Graal с другими JVM языками, такими как Scala и Kotlin.

Подробнее..
Категории: Python , Java , Graalvm , Performance optimization

Онлайн-лекция Реактивные и нативные приложения на Java Spring и Quarkus

25.07.2020 14:22:36 | Автор: admin
image

28 июля приглашаем на онлайн-лекцию о разработке приложений на Java Spring, Quarkus, Vert.x и GraalVM с деплоем в MicroK8s.

В программе лекции: Сергей Кошкинов и Андрей Смирнов покажут процесс создания приложения на Java-фреймворке Quarkus с деплоем в MicroK8s. А также сравнят производительность и потребления памяти приложений на Spring WebFlux, Spring Boot, Quarkus, Quarkus+Vert.x и скомпилированными в native code с помощью GraalVM.

Зарегистрироваться



Об экспертах


Сергей Кошкинов разработчик в МегаФоне, Oracle Certified Professional Java Programmer.

Андрей Смирнов разработчик в МегаФоне. В прошлом преподавал программирование в ННГУ им. Н. И. Лобачевского.

По теме:

Подробнее..

Вышла Java 15

15.09.2020 18:11:52 | Автор: admin

Сегодня в свет вышла новая, 15-я версия платформы Java.


Скачать JDK 15 можно по следующим ссылкам:


  • Oracle JDK (проприетарная версия, обратите внимание на ограничения в использовании).
  • OpenJDK (бесплатная версия)

В новый релиз попало 14 JEP'ов и сотни более мелких улучшений. Если хочется ознакомиться с полным списком изменений с точностью до всех JIRA-тикетов, то их можно посмотреть на сайте Алексея Шипилёва. Также если интересны все изменения API, то их можно посмотреть здесь.



Перечислим JEP'ы, которые попали в Java 15:


Язык


Блоки текста (JEP 378)


Блоки текста, которые появились в Java 13 и прошли два preview, теперь стали стабильной синтаксической конструкцией. Это значит, что в Java теперь две постоянные конструкции, которые появились с выхода Java 11: выражения switch и блоки текста.


Паттерн-матчинг для оператора instanceof (второе preview) (JEP 375)


Улучшенный оператор instanceof, который появился в Java 14, перешёл во второе preview без изменений. Напомним, что режим preview существует в Java для нововведений, которые находятся в предварительном статусе, т.е. могут измениться несовместимым образом или даже совсем исчезнуть, и для их включения необходим специальный флаг --enable-preview. Паттерн-матчинг для instanceof мы подробно рассматривали в этой статье.


Записи (второе preview) (JEP 384)


Записи, которые также появились в Java 14, тоже остались в режиме preview. Изменений по сравнению с прошлой версией немного: убрано ограничение, что канонический конструктор должен быть public, а также разрешены локальные перечисления и интерфейсы.


Sealed классы (preview) (JEP 360)


В Java появилось языковое нововведение: запечатанные классы. Помечаются такие классы модификатором sealed, после чего круг классов, которые могут наследоваться от данного класса, становится ограниченным. sealed классы мы подробно рассматривали в этой статье.


JVM


ZGC (JEP 377)


ZGC, который появился в Java 11 в экспериментальном статусе, теперь официально готов к продуктовой разработке. Напомним, что ZGC это сборщик мусора, который нацелен на маленькие паузы (< 10мс) и готовность работать в условиях огромных куч (> 1TB).


Shenandoah (JEP 379)


Shenandoah, ещё один низкопаузный сборщик мусора и конкурент ZGC, теперь также имеет статус готового к продуктовой разработке. Shenandoah впервые появился в Java 12. Также недавно стало известно, что Shenandoah был бэкпортирован в JDK 11, который является текущим LTS-релизом Java. Это значит, что чтобы его использовать, необязательно обновляться до JDK 15, а достаточно обновиться до JDK 11.0.9, которая выйдет 20 октября 2020 года.


Disable and Deprecate Biased Locking (JEP 374)


Biased Locking, который много лет существовал в JDK, было решено убрать из-за сложности поддержки и неочевидных преимуществ этой оптимизации. Начиная с этого релиза, опция -XX:+UseBiasedLocking отключена по умолчанию, а при её использовании и всех её связанных опций будет выдаваться предупреждение. Про мотивы отключения Biased Locking рассказал Сергей Куксенко в подкасте Hydra.


Удаление портов Solaris и SPARC (JEP 381)


Порты JDK на Solaris/SPARC, Solaris/x64 и Linux/SPARC, которые стали deprecated for removal в Java 14, теперь удалены окончательно. Удаление этих портов упростит и ускорит разработку JDK.


API


Скрытые классы (JEP 371)


Появился новый тип классов, называемых скрытыми. На скрытые классы не могут прямо ссылаться другие классы, и всё их использование может осуществляться только через рефлексию. Также их нельзя обнаружить по имени, и их методы не появляются в стек-трейсах. Создаются такие классы с помощью нового метода Lookup.defineHiddenClass().


Удаление движка JavaScript Nashorn (JEP 372)


Движок Nashorn, который стал deprecated for removal в Java 11, теперь удалён окончательно. В качестве замены Nashorn теперь придётся искать другой движок JavaScript, например, GraalVM JavaScript или Rhino.


Reimplement the Legacy DatagramSocket API (JEP 373)


Реализации старых сокетов из JDK 1.0 java.net.DatagramSocket and java.net.MulticastSocket были полностью заменены на более простые, современные и легкоадаптируемые к виртуальным нитям, которые планируется ввести в язык в рамках проекта Loom. Ранее в Java 13 были переписаны java.net.Socket и java.net.ServerSocket.


Foreign-Memory Access API (Second Incubator) (JEP 383)


API для доступа вне кучи Java, которое появилось в Java 14 в статусе модуля-инкубатора, остаётся в этом статусе.


Deprecate RMI Activation for Removal (JEP 385)


Устаревшая и малоиспользуемая часть RMI, которая называется RMI Activation, стала deprecated for removal.


Edwards-Curve Digital Signature Algorithm (EdDSA) (JEP 339)


Современный алгоритм с открытым ключом для создания цифровой подписи EdDSA реализован в Java.


Java 15, как и 12, 13, 14, является STS-релизом, и у неё выйдет только два обновления.

Подробнее..
Категории: Java , Graalvm , Java15 , Java14 , Java13 , Java12 , Sealed , Nashorn , Zgc , Shenandoah

Категории

Последние комментарии

  • Имя: Макс
    24.08.2022 | 11:28
    Я разраб в IT компании, работаю на арбитражную команду. Мы работаем с приламы и сайтами, при работе замечаются постоянные баны и лаги. Пацаны посоветовали сервис по анализу исходного кода,https://app Подробнее..
  • Имя: 9055410337
    20.08.2022 | 17:41
    поможем пишите в телеграм Подробнее..
  • Имя: sabbat
    17.08.2022 | 20:42
    Охренеть.. это просто шикарная статья, феноменально круто. Большое спасибо за разбор! Надеюсь как-нибудь с тобой связаться для обсуждений чего-либо) Подробнее..
  • Имя: Мария
    09.08.2022 | 14:44
    Добрый день. Если обладаете такой информацией, то подскажите, пожалуйста, где можно найти много-много материала по Yggdrasil и его уязвимостях для написания диплома? Благодарю. Подробнее..
© 2006-2024, personeltest.ru