Upgrade to Pro — share decks privately, control downloads, hide ads and more …

GraalVM 最新事情 / graalvm-what's-new

GraalVM 最新事情 / graalvm-what's-new

Oracle Cloud Hangout Cafe Season 6 #2
https://ochacafe.connpass.com/event/259128/

セッション動画: https://youtu.be/Ex4ttuTH2Lk

oracle4engineer

October 05, 2022
Tweet

More Decks by oracle4engineer

Other Decks in Technology

Transcript

  1. GraalVM 最新事情 Oracle Cloud Hangout Cafe - Season 6 #2

    Tadahisa Kotegawa Senior Director, Solutions Architect Oracle Corporation Japan October 5th , 2022
  2. Copyright © 2022, Oracle and/or its affiliates 2 あれから 3年

    経ちました… 2019年9月19日開催 https://ochacafe.connpass.com/event/140792/
  3. Copyright © 2022, Oracle and/or its affiliates 3 1. GraalVM

    のおさらい 2. ネイティブ・イメージ 3. 言語ランタイムとツール 4. まとめ Agenda
  4. Copyright © 2022, Oracle and/or its affiliates 4 自己紹介 古手川

    忠久 日本オラクル株式会社 ソリューションアーキテクト本部 Oracle Developer Days 2022 Spring 【パネルディスカッション】徹底討論!マイクロサービス開発におけるJavaの最適解 https://developer.oracle.com/jp/developer-days-2022-may/on-demand/#cloudday CodeZine 「日本のマイクロサービスの現在地は? Javaはマイクロサービスに向いているか?」 https://codezine.jp/article/detail/16148 @tkotegaw tkote oracle-japan @tkote
  5. Copyright © 2022, Oracle and/or its affiliates 6 新たな JIT

    コンパイラがもらたす 高い Java パフォーマンス • インフラコストの削減 • アプリコードの変更不要 • Javaエコシステムの生産性をそのまま 活用可能 多言語 (Polyglot) プログラミング • 各種言語の高性能ランタイム Node.js, Python, R, Ruby, C/C++, etc. • 複数の言語をひとつのアプリケーション から呼び出せる • 独自の言語実装/実行が可能 AOT コンパイラによる ネイティブ・イメージの作成 • 小さなメモリ・フットプリント • 起動時間の短縮 (ウォームアップなし) • コンテナ・アプリに最適 プロファイル、デバッグ、モニタリングを 支援する先進的なツール群 • VS Code Extensions • Chrome Debugger • VisualVM, etc. GraalVMとは ? 高性能なJDKディストリビューション
  6. Copyright © 2022, Oracle and/or its affiliates 7 Javaで記述されたJust-in-Time (JIT)

    コンパイラ = Javaバイトコードをマシン・コードに変換する • JVMコンパイラ・インタフェース (JVMCI) をサポートする Java HotSpot VM と統合されている JVMで実行されるプログラムのパフォーマンスを最適化 • 高度に抽象化されたプログラムのパフォーマンス向上 - stream, lambda など • 低レベルのコード、I/O、メモリ割当て、ガベージ・コレクションなどの比重が高いコードでは改善効果小 • GraalVM EE には更に高度な最適化が含まれる GraalVM コンパイラ 従来からの Java アプリケーション (JVM上で動作するアプリケーション) もパフォーマンス向上が期待できる C2 JIT コンパイラ: C1 JIT コンパイラが始動後、プロファイリングメトリクスが収集されてから始動する JIT コンパイラで、より最適化されたコードを生成する OS Java SE Java Application HotSpot VM C2 JIT コンパイラ OS GraalVM Java Application HotSpot VM GraalVM JIT コンパイラ 置き換え 2つの実行モード - libgraal (default) - jargraal (-XX:-UseJVMCINativeLibrary)
  7. Copyright © 2022, Oracle and/or its affiliates 8 ネイティブ・イメージ =

    必要なコードと依存関係のみを含んだネイティブ実行形式のJavaアプリケーション • Substrate VM が含まれる = ガベージコレクタやスレッドスケジューラといった実行時コンポーネントを提供するVM実装 ネイティブ・イメージ・ビルダー (native-image) でネイティブ・イメージを生成 • 通常のJavaアプリケーションを起動するように起動 • META-INF/native-image/ 配下 (サブディレクトリ含) のすべての構成ファイルを自動的に取得 AOT (ahead-of-time) コンパイラ アプリケーションの起動を高速化し、フットプリントを縮小する → Javaアプリのコンテナ化 (マイクロサービス) に適する ネイティブ・イメージ Substrate VM Java Application (構成ファイル) jar jar jar class native-image コマンド 構成オプション MainClass META-INF/native-image/**/* Java ソースコード Maven リポジトリ $JAVA_HOME/bin/native-image <構成オプション> -jar excutable.jar $JAVA_HOME/bin/native-image <構成オプション> -cp <classpath> fully.qualified.MainClass リフレクションやリソースなどネイティブ・イメージのビルドに必要な構成情報
  8. Copyright © 2022, Oracle and/or its affiliates 9 イメージのビルド時に構成情報が必要なもの •

    Dynamic Class Loading • Reflection • Dynamic Proxy • JNI (Java Native Interface) • Serialization 動作が異なる可能性のある機能 • Signal Handlers • Class Initializers • Finalizers • Threads • Unsafe Memory Access • Debugging and Monitoring サポートされないもの • Invoke Dynamic Bytecode and Method Handles • Security Manager AOT コンパイラの制約 後述するトレース・エージェントを使って構成ファイルの 自動生成が可能 (完全ではないので注意)
  9. Copyright © 2022, Oracle and/or its affiliates 10 GraalVM は

    Truffleフレームワークを使った一般的な言語用の高性能なランタイムを提供 • Java、JavaScriptおよびNode.js、LLVM言語 (C, C++, Rust)、Python、R、Ruby、WebAssembly ポリグロット機能 - 複数のプログラミング言語を単一のアプリケーションに混在できる 言語実装のためのプラットフォーム • 独自の言語実装(インタープリタ)を開発して GraalVM上で実行することが可能 Language Implementation Framework (Truffle) Truffle 言語実装フレームワーク GraalVM JIT Compiler Language Implementation Framework (Truffle) GraalVM LLVM bitcode interpreter Java on Truffle
  10. GraalVM JIT Compiler Language Implementation Framework (Truffle) GraalVM LLVM bitcode

    interpreter Java on Truffle Copyright © 2022, Oracle and/or its affiliates 11 Truffleフレームワークを使ってJavaで記述された Java バイトコード・インタープリタ JavaSE8 および JavaSE11 の実装 GraalVMエコシステムの他の言語(JavaScript、Ruby、Python、R)と同じメモリ空間でデータをやり取り可能 ホスト JavaVM とは別のコンテキストで Java バイトコードを実行 実行中のアプリケーションを再起動することなくコードのリロード (HotSwap) が可能 Java on Truffle
  11. Copyright © 2022, Oracle and/or its affiliates 12 • GraalVM

    EE は Java SE Subscription に含まれる • Oracle Cloud Infrastructure (OCI) の利用者は GraalVM EE を OCI 上で無償利用可能(ライセンスとサポート) GraalVM のエディション https://www.graalvm.org/downloads/ GraalVM 22.2 Community Edition (CE) Enterprise Edition (EE) ライセンス GNU General Public License V2 with the “Classpath” Exception 商用ライセンス -------------------------- Oracle Technology Network (OTN) ライセンス (開発/テスト) ベースJDKs OpenJDK 11.0.16 and 17.0.4 Oracle JDK 8u341, 11.0.16 and 17.0.4 サポート コミュニティ・サポート Oracleによる商用サポート Renaissance Suite (JVMベンチマーク) で 計測した対 OpenJDK スピードアップ 1.04x 1.3x Docker コンテナ・イメージ ✔ ✔ 特許取得の高度なコンパイラ最適化 ✔ ネイティブ・イメージの最適化 - 圧縮されたポインタによる低メモリ使用 - プロファイルガイド最適化による性能向上 - G1ガベージ・コレクションによる低遅延 ✔
  12. Copyright © 2022, Oracle and/or its affiliates 14 Community Edition

    • 機能リリース (Feature Release) • 3か月毎 (2,5,8,11月)のマイナーリリース • 最新の機能リリースがサポート対象 • 年次リリース (Annual Release Train) • 暦年毎に構成される一連の機能リリース • 21.x, 22.x • 年次リリースには4つの機能リリース(0-3) • 年次リリースの最後の機能リリース(e.g. 21.3)は12か月 間、バグと脆弱性の修正を提供 • クリティカルパッチアップデート(CPU) • Open JDK にもとづく Enterprise Edition • 機能リリース (Feature Release) • 同左 • 年次リリース (Annual Release Train) • 年次リリースの最後の機能リリース(yy.3)は18か月間 (メンテナンスリリース)のバグ修正を受けつける • 長期サポートリリース (LTS) • 安定した本番環境向け • 2年ごと • 最新LTS 21.3、次回予定LTS 23.3 • クリティカルパッチアップデート (CPU) • オラクルのCPUリリースに従う GraalVM のバージョン・ロードマップとサポート・ポリシー 詳しくはこちらを参照 CE: https://www.graalvm.org/release-notes/version-roadmap/ EE: https://docs.oracle.com/en/graalvm/enterprise/22/docs/version-roadmap/ ※ EEの明確なサポート期限(Premier/Extended)は オラクルライフタイムサポートポリシーに記載されています
  13. ポリグロット・アプリケーション GraalVM上のホスト言語 (JavaScript/Node.js, R, Ruby, Python, C) から Javaクラスにアクセス GraalVM

    GraalVM Copyright © 2022, Oracle and/or its affiliates 15 JVMランタイム HotSpot VM 上の JIT コンパ イラーとして GraalVMコンパイ ラーを使用して実行 ネイティブ・イメージ Javaバイトコードをネイティブ実 行可能ファイルまたはネイティブ 共有ライブラリにコンパイルして 実行 Java on Truffle Truffleフレームワーク上に構築 された、JVMバイトコード・イン タプリタの実装を使用して実行 ひとまずまとめ:Java アプリケーションは GraalVM でどう実行できるのか? OS GraalVM Java Application (byte code) Native Image Substrate VM Java Application (AOT) OS HotSpot VM GraalVM JIT Compiler Truffle Java on Truffle OS Java Application HotSpot VM GraalVM JIT Compiler Truffle OS Polyglot Application JS,R,Ruby,Python,LLVM Java Class HotSpot VM GraalVM JIT Compiler
  14. Copyright © 2022, Oracle and/or its affiliates 17 Java アプリケーションの実行方法あれこれ

    # GraalVMで実行 – 通常の実行方法 $ java –cp target/demo-1.0.jar com.example.App Hello World! # Graal JIT コンパイラを敢えて無効にして実行する $ java -XX:-UseJVMCICompiler -cp target/demo-1.0.jar com.example.App Hello World! # Java on Truffle (Truffle上のJVMバイトコード・インタプリタ) で実行する $ java -truffle -cp target/demo-1.0.jar com.example.App Hello World! # Java on Truffle は単一のファイルであればソースファイルも実行できる! $ java -truffle src/main/java/com/example/App.java Hello World! # Java on Truffle で異なるJavaのインストール先にある実行モジュール(=jarとライブラリ)を使用して実行する – バージョンが違ってもOK! $ java -truffle --java.JavaHome=/home/opc/opt/jdk-11.0.15.1 -cp target/demo-1.0.jar com.example.App Hello World! # ネイティブ・イメージの作成 (Maven native-maven-plugin を利用) と実行 $ mvn -Pnative package -DskipTests=true $ ./target/demo Hello World! # Javascript コードから Javaクラスにアクセス $JAVA_HOME/bin/js --jvm -e 'Java.type("java.lang.System").out.println("Hello World!")' Hello World!
  15. $ $JAVA_HOME/bin/gu GraalVM Component Updater v2.0.0 Usage: gu info [-cClLnprstuvV]

    <param> print info about a specific component (from a file, a URL or a catalog) gu available [-aClvV] <expr> list components available in a catalog gu install [-0CcDfiLMnosruvyxY] <param> install a component package gu list [-clv] <expression> list installed components, or components from a catalog gu remove [-0DfMxv] <id> uninstall a component gu upgrade [-cCnLsuxSd] [<ver>] [<cmp>] upgrade to a recent GraalVM or edition gu rebuild-images ... (省略) $ $JAVA_HOME/bin/gu available Downloading: Component catalog from www.graalvm.org ComponentId Version Component name Stability Origin --------------------------------------------------------------------------------------------------------------------------------- espresso 22.1.0 Java on Truffle Supported github.com espresso-llvm 22.1.0 Java on Truffle LLVM Java librSupported github.com llvm-toolchain 22.1.0 LLVM.org toolchain Supported github.com native-image 22.1.0 Native Image Early adopter github.com nodejs 22.1.0 Graal.nodejs Supported github.com python 22.1.0 Graal.Python Experimental github.com R 22.1.0 FastR Experimental github.com ruby 22.1.0 TruffleRuby Experimental github.com wasm 22.1.0 GraalWasm Experimental github.com Copyright © 2022, Oracle and/or its affiliates 18 GraalVM Component Updater GraalVMの言語ランタイムやユーティリティを管理するコマンドライン・ツール 使用の際は確認下さい
  16. Copyright © 2022, Oracle and/or its affiliates 21 通常 Java

    を起動するのと同様な起動方法 • 非常にたくさんのオプションあり… 構成ファイルの適用・埋込み • META-INF/native-image/ 下(サブディレクトリ含)のすべての構成ファイルを取得してコマンドライン引数を構築 • プロジェクトJARファイルに埋め込むことで構成を適用・配布することができる → JAR間でバッティングしないようにするための慣習: グループID & アーティファクトID で階層化する ネイティブ・イメージ ビルダー META-INF/ └── native-image └── groupID └── artifactID └── native-image.properties, etc. $ native-image [options] class [imagename] [options] $ native-image [options] -jar jarfile [imagename] [options] $ native-image [options] --module <module>[/<mainclass>] [options]
  17. Copyright © 2022, Oracle and/or its affiliates 22 クラスの初期化処理はパフォーマンスに大きな影響を及ぼす •

    アプリケーション起動時の処理量が多い → 起動所要時間が長くなる AOTによる最適化 • イメージのビルド中に特定のクラスを初期化して、実行時の初期化とチェックを不要にする • 初期化されたクラスのすべての静的状態情報がイメージに格納される ネイティブ・イメージ ビルダーはビルド時の初期化を試みる • 初期化のタイミングによって動作が異なる可能性はある(前述) • オプションで個別に制御可能 --initialize-at-build-time=<カンマ区切りのクラス名orパッケージ名> --initialize-at-run-time=<カンマ区切りのクラス名orパッケージ名> ネイティブ・イメージ ビルダー ビルド時におけるクラス初期化の意味
  18. Copyright © 2022, Oracle and/or its affiliates 23 JIT AOT

    • OS が JVM 実行ファイルをロードする • VM がファイルシステムからクラスをロードする • バイトコードが検証される • バイトコードの解釈が開始される • 静的イニシャライザの実行 • 第1層コンパイル (C1) • プロファイリングメトリクスの収集 • ... (しばらくの後) • 第2層コンパイル (C2/Graal コンパイラ) • 最適化されたマシンコードによる実行 • OS が実行ファイルと設定済ヒープをロードする • 最適化されたマシンコードでアプリケーションが起動する JIT と AOT の起動プロセスの違い ネイティブ・イメージの起動所要時間が短いワケ 出典: Javaに革命を起こすGraalVM Native Image https://www.infoq.com/jp/articles/native-java-graalvm/ 起動プロセスが短いのは分かったけど 静的解析によるコード生成だと プロファイリングによる最適化がされないので 起動後のパフォーマンスはJITコンパイラに 分がありそうな気もする…
  19. Copyright © 2022, Oracle and/or its affiliates 24 プロファイリング・データを事前に収集し、ネイティブ・イメージ ビルダーにフィードすることによって、ネイティブ・イメージのパフォー

    マンス(スループット向上)が最適化される。 手順 1. Javaプログラムのコンパイル → クラスファイルの作成 2. --pgo-instrument オプションを追加してプロファイリング用ネイティブイメージを作成 3. プロファイリング用ネイティブイメージを実行 → プロファイル情報がprofile.iprofに保存 4. プロファイル情報を使って、最適化されたネイティブ・イメージを作成 5. 最適化されたネイティブ・イメージを実行 プロファイルに基づく最適化 (EEのみ) profile-guided optimizations .java .class Native image (プロファイル用) Profile.iprof Native image (最適化済) javac native-image --pgo-instrument (run) native-image --pgo=profile.iprof (run) $ javac OptimizedImage.java $ native-image --pgo-instrument OptimizedImage $ ./optimizedimage $ native-image --pgo=profile.iprof OptimizedImage $ ./optimizedimage
  20. Copyright © 2022, Oracle and/or its affiliates 25 タイプ ビルド時オプション

    説明 シリアル GC (デフォルト) • 最適化目標=メモリ・フットプリントおよび Java ヒープ・サイズを最小化 • 停止とコピーを行う単純な GC (非パラレル、非同時実行) G1 GC --gc=G1 • 最適化目標=レイテンシとスループットの間のバランス • マルチスレッド GC、stop-the-world の停止を減らしてレイテンシーを改善 • EE でのみ使用可能 / Linux for AMD64 向けイメージのみサポート Epsilon GC --gc=epsilon • ガベージコレクションを行わない=割り当てられたメモリを解放しない • 少量のメモリしか割り当てない非常に短時間で実行されるアプリケーション • GraalVM 21.2 以降で使用可能 ネイティブ・イメージのガベージ・コレクタ
  21. Copyright © 2022, Oracle and/or its affiliates 26 システム構成と使用されている GC

    に基づいて、適切な Java ヒープ設定が自動的に決定される ネイティブ・イメージのコマンド ライン オプションでヒープサイズを明示的に設定することも可能 • -Xmx - 最大ヒープ サイズ (バイト単位) • -Xms - 最小ヒープ サイズ (バイト単位) • -Xmn - young 世代のサイズ (バイト単位) イメージのビルド時にデフォルトのヒープ設定を事前に構成することもできる (GraalVM 20.0以降) 指定された値は、実行時にデフォルト値として使用される • -R:MaxHeapSize - 最大ヒープサイズ (バイト単位) • -R:MinHeapSize - 最小ヒープサイズ (バイト単位) • -R:MaxNewSize - young世代のサイズ (バイト単位) ネイティブ・イメージのヒープサイズ $ ./demo –Xms384m –Xmx1g
  22. Copyright © 2022, Oracle and/or its affiliates 27 静的分析で検出しきれない動的機能の使用に関する情報が必要なケースはままある →

    人力で動的機能を全て洗い出して設定するのは非常に大変 & 100%補足は困難 トレース・エージェント • 構成ファイルの準備を容易にする • GraalVM javaコマンドのコマンドラインで有効にできる 実行中のJava VMから、クラス、メソッド、フィールド、リソースを参照したりプロキシ・アクセスをリクエストするすべてのコー ルをインターセプトして、ネイティブ・イメージ作成のための構成情報を出力する • オプション config-output-dir=... 構成ファイルの出力先ディレクトリ config-merge-dir=... ファイルを上書きせずにマージするときはこちらを使用 config-write-period-secs=... 定期的な書き込みを行う秒数 config-write-initial-delay-secs=... 最初の書き込みまでの時間 caller-filter-file=...コール元メソッドによるフィルタ設定 access-filter-file=...アクセス対象によるフィルタ設定 トレース・エージェント $JAVA_HOME/bin/java -agentlib:native-image-agent=<options…> -cp … MainClass
  23. Copyright © 2022, Oracle and/or its affiliates 28 ネイティブ・イメージ作成のためのビルド・プロセスを支援するプラグイン •

    ネイティブ・イメージの作成 • JUnitを使ったテストのサポート • テストもネイティブ・イメージにコンパイルして実行することができる • トレース・エージェントの起動 • アプリケーション実行時、テスト時のエージェント有効化 • 到達可能性メタデータリポジトリ (GraalVM Reachability Metadata Repository) のサポート (0.9.13以降) • 静的分析によって検出されない要素を含めるためのメタデータリポジトリ github.com/oracle/graalvm-reachability-metadata/tree/master/metadata • ライブラリ/フレームワークのメタデータをリポジトリで共有・再利用することによってビルド作業を効率化 • GraalVM ネイティブ ビルド ツールはメタデータ・リポジトリの使用を有効化できる • native-maven-plugin の <configuration> で URL を指定する ネイティブ ビルド ツール Maven プラグイン, Gradle プラグイン pom.xml で native-maven-plugin を “native” プロファイル内で package/testフェーズに 紐付けている $ mvn -Pnative -Dagent=true test $ mvn –Pnative test $ mvn -Pnative (-DskipTests=true) (-DskipNativeTests=true) package
  24. Copyright © 2022, Oracle and/or its affiliates 29 自動検出 –

    ある程度のものはネイティブ・イメージ ビルダーが自動的に検出してくれる • Class.forName(String) の Stringがリテラルの場合など 構成ファイル • 自力で記述する and/or agentを使って構成ファイルを出力する org.graalvm.nativeimage.hosted.Feature インターフェースの実装クラスを作成する • 構成ファイル相当の情報を Java クラスとして記述する ネイティブ・イメージ構成情報の渡し方 [{ "name": "com.example.Hello", "methods": [ { "name": "<init>", "parameterTypes": [] }, { "name": "say", "parameterTypes": [] } ] }] reflect-config.json package com.example; import org.graalvm.nativeimage.hosted.Feature; import org.graalvm.nativeimage.hosted.RuntimeReflection; public class RuntimeReflectionRegistrationFeature implements Feature{ public void beforeAnalysis(BeforeAnalysisAccess access) { try { RuntimeReflection.register(Hello.class); RuntimeReflection.register(Hello.class.getDeclaredConstructor()); RuntimeReflection.register(Hello.class.getDeclaredMethod("say")); } catch (NoSuchMethodException /*| NoSuchFieldException*/ e) {} } } =
  25. Copyright © 2022, Oracle and/or its affiliates 30 ネイティブ・イメージでも利用可能だが制限がある •

    カスタム/システム・イベント、ディスク・ベースのレコーディング • スタックトレース、メモリ・リーク・ディテクション等は未実装 • GraalVM JDK 11でビルドされたネイティブ・イメージのみ 使い方 • ビルド時 native-image -H:+AllowVMInspection JavaApplication • 実行時 ./javaapplication -XX:+FlightRecorder -XX:StartFlightRecording="filename=recording.jfr(,…)“ • JFRシステムのログ設定のオプションもあり: -XX:FlightRecorderLogging=[tag1[+tag2...] ネイティブ・イメージと JDK Flight Recorder
  26. Copyright © 2022, Oracle and/or its affiliates 31 デモ: ネイティブ・イメージを作成する

    ネイティブ・イメージ・ビルダー トレース・エージェント Maven プラグイン リフレクション対応 – 構成ファイル / Feature
  27. Copyright © 2022, Oracle and/or its affiliates 33 「ネイティブ・イメージ対応」 の意味するところ

    • ネイティブ・イメージの作成で引っかかりそうな動的機能を使わないようにフレームワークが作られている • e.g.) アノテーションの処理を実行時でなくビルド時に行う • 構成ファイルや Feature クラスが ライブラリの jar ファイルに同梱されている マイクロサービス・フレームワークのネイティブ・イメージ対応 メジャーなマイクロサービス・フレームワークはネイティブ・イメージに対応している状況 但し、自分で import する 3rd party ライブラリなどがネイティブ・イメージに 対応している訳ではないので、楽観的過ぎてはダメ ( トレース・エージェントのお陰でずっと楽にはなりました… )
  28. Copyright © 2022, Oracle and/or its affiliates | Confidential: Internal/Restricted/Highly

    Restricted 34 Helidon = マイクロサービス向けの軽量Javaフレーム ワーク、OracleがホストするOSSプロジェクト ネイティブ・イメージの作成をサポート SE, MP ともに各コンポーネントのネイティブ・イメージ 対応状況に関するリストを提供 ポイント • Helidon の流儀を崩さない “mvn package –Pnative-image” • トレース・エージェントを使って構成ファイルを生成 • 配置場所の慣習に従って配置 • 最後はトライ&エラーで設定を追加 Helidon アプリケーションをネイティブ・イメージにして動かす helidon.io https://qiita.com/tkote/items/a7f9a7b3ba9633cd83c7 $ mvn clean package -Pnative-image
  29. Copyright © 2022, Oracle and/or its affiliates 35 デモ:Helidon MP

    ネイティブ・イメージ Hibernate (JPA) を使って Oracle データベースにアクセスする Java アプリケーションを ネイティブ・イメージにコンパイルして動かす
  30. Copyright © 2022, Oracle and/or its affiliates 36 起動時間が早い →

    コールド・スタート問題を緩和できる • コールド・スタートとは? • 初回の呼び出し(アプリケーションの設定値変更後を含む)が遅い ← コンテナを新規に準備するため • 一定時間アイドル状態が続いた後での呼び出しが遅い ← コンテナが一旦破棄されているため初回呼び出しと同じになる • その要因は? • コンテナ起動に関する準備に要する時間 → FaaS が提供する Provisioned Concurrency 機能で対策可能 • コンテナ内のアプリケーションのウォームアップに要する時間 → Java の場合、このオーバーヘッドが大きい メモリ・フットプリントが小さい → 低コストで運用できる • OCI Functions の場合、課金単位は 「リクエスト数 + ギガバイト・メモリ-秒」 ネイティブ・イメージと FaaS (Function as a Service) 相性がいいとされている理由 コンテナ起動時間 Javaアプリのウォームアップ時間 コールド・スタート問題の緩和! Provisioned Concurrency Native Image
  31. Copyright © 2022, Oracle and/or its affiliates 37 OCI Functions

    フルマネージドなサーバレス基盤(FaaS) • 様々な用途で利用可能 • イベント処理、RESTサーバー、API GW認証処理、etc. • 実行時のみ課金、インフラ管理不要、自動スケール オープンソースのFn Projectをベース • Dockerコンテナの可搬性、ロックイン無し 開発者視点のシンプルな開発フロー • CLI: fn [ init | build | deploy | … ] • 開発キット(FDK)を提供 • Java, Node.js, Python, Go, Ruby Function Development Kit for Java github.com/fnproject/fdk-java (オープンソース) 入出力、データバインディング、Junitテスト機能などのAPIとラ ンタイムを提供し、Dockerイメージ作成をサポート OCI Functions でネイティブ・イメージを動かす (1) OCI Functions とは / FDKで作成されるコンテナ・イメージ Functions FDKで作成されるコンテナ・イメージと OCI Functions ランタイムの構成 OCI Functions コンテナ・ホスト・インスタンス unix domain socket /tmp/xxxxx.sock Fn コンテナ・イメージ OS libfnunixsocket.so JVM runtime-x.x.x.jar api-x.x.x.jar アプリケーション jar リクエストを fwdする 何か FDKで 作成される もの 3rd party jars JNI
  32. $ mvn test Copyright © 2022, Oracle and/or its affiliates

    38 ネイティブ・イメージのコンテナは作れそう • カスタム Dockerfile で fn build すれば OK • この中で native-image ツール (mvn) を動かす • libfnunixsocket.so は、FDKランタイム・イメージ からコピーする ネイティブ・イメージ 構成ファイルをどう生成するか? • ローカル環境では、fn コンテナの起動は難しい • 諸々の前提条件が必要なのでかなりタフ • → テスト・ハーネスを使ってアプリケーションをテストす るタイミング(mvn test)で agent を起動 • maven-surefire-plugin のオプションで – agentlib:xxx を指定する* • access-filter.json でJUnit系の構成情報をフィルタ 必要に応じて、マニュアルで構成ファイルを編集・追加 OCI Functions でネイティブ・イメージを動かす (2) ネイティブ・イメージの Fn コンテナを作成するための方法を紹介 Fn コンテナ・イメージ OS libfnunixsocket.so JVM runtime-x.x.x.jar api-x.x.x.jar アプリケーション jar 3rd party jars JNI ネイティブ・イメージ ここを ネイティブ・イメージに コンパイルする ローカルテスト実施に agent を起動して ネイティブ・イメージ構成ファイルを自動生成 自前の Dockerfile でコンテナ作成 * native-maven-plugin 使うより融通が利く (設定ファイルを上書きせずマージするオプションを指定できる) ので、こちらの方法を取りました 構成 ファイル $ fn build
  33. Copyright © 2022, Oracle and/or its affiliates 39 OCI Functions

    でネイティブ・イメージを動かす (3) fn build で使用する Dockerfile ### STEP 1 – ネイティブ・イメージ・ビルダの入ったパブリック・コンテナ・イメージを使ってソースコードをビルドして、アプリケーションのネイティブ・イメージを作成する FROM ghcr.io/graalvm/native-image:ol8-java17-22.1.0 as native-image-build WORKDIR /function ADD pom.xml pom.xml ADD mvnw mvnw ADD .mvn .mvn RUN ["./mvnw", "package", "-DskipTests=true"] ADD src src RUN ["./mvnw", "-Pnative", "package", "-DskipTests=true"] # ネイティブ・イメージ (func) は /function/target 下に作成される ### STEP 2 - fdk ランタイム・イメージから libfnunixsocket.so をコピーするための準備 FROM fnproject/fn-java-fdk:jre11-latest as fdk-runtime # libfnunixsocket.so is located under /function/runtime/lib ### STEP 3 – fn 仕様のコンテナ・イメージを作成する func + libfnunixsocket.so FROM container-registry.oracle.com/os/oraclelinux:8-slim WORKDIR /function COPY --from=native-image-build /function/target/func . # copy native image COPY --from=fdk-runtime /function/runtime/lib/libfnunixsocket.so . # copy libfnunixsocket.so ENTRYPOINT ["./func", "-XX:MaximumHeapSizePercent=80", "-Djava.library.path=/function"] CMD [ "com.example.fn.HelloFunction::handleRequest" ]
  34. Copyright © 2022, Oracle and/or its affiliates 40 デモ:OCI Functions

    でネイティブ・イメージを動かす Eclipselink (JPA) を使って Oracle データベースにアクセスする Java アプリケーションを ネイティブ・イメージにコンパイルして OCI Functions で動かす Autonomous Database Functions Key Vault DB PW resource principal
  35. Copyright © 2022, Oracle and/or its affiliates 41 Micronaut (micronaut.io)

    • マイクロサービス/サーバーレスアプリケーションを構築するためのJVMベースのOSSフレームワーク ネイティブ・イメージを作成するためのガイドが各種あり (guides.micronaut.io) • CREATING YOUR FIRST MICRONAUT GRAAL APPLICATION • DEPLOY A MICRONAUT FUNCTION (SERVERLESS) APPLICATION TO ORACLE CLOUD • DEPLOY A MICRONAUT HTTP API GATEWAY FUNCTION (SERVERLESS) APPLICATION TO ORACLE CLOUD ↑ ちなみに 「MICRONAUT + ORACLE CLOUD」 のセクションに、 MySQL, IDCS, Secrets, Database, Streaming, Email Delivery など、各種サービスとのインテグレーションに関するガイドがあります! (たいていのものはバイトコードに加えてネイティブ・イメージの作成まで解説アリ) Micronaut ネイティブ・イメージを OCI Functions で動かす AOTに優しいフレームワーク – Javaアノテーションの処理を実行時からコンパイル時にシフト これがミソ = HTTP Verb/Path に応じた制御部分をフレームワーク側でやってくれる=開発・保守生産性向上 → Java FDK ではやってくれない部分 @Delete("/{countryId}") public void deleteCountry(int countryId) { … これを 待ってた!
  36. Copyright © 2022, Oracle and/or its affiliates 42 デモ:Micronaut native-image

    FaaS API Server このデモ = ガイド "DEPLOY A MICRONAUT HTTP API GATEWAY FUNCTION (SERVERLESS) APPLICATION TO ORACLE CLOUD" + ガイド "ACCESS A DATABASE WITH JPA AND HIBERNATE" API Gateway Autonomous Database Functions Key Vault User DB PW GET POST PUT DELETE resource principal
  37. Copyright © 2022, Oracle and/or its affiliates 43 デモ:Micronaut native-image

    FaaS API Server API Gateway の設定 API Gateway Autonomous Database Functions Key Vault User DB PW GET POST PUT DELETE resource principal /country から始まる任意のパスで GET/POST/PUT/DELETE メソッドの HTTP リクエストは sandbox アプリケーションの mn-function-http ファンクションに ルーティングする
  38. Copyright © 2022, Oracle and/or its affiliates 45 • ゲスト言語の実行環境=コンテキスト

    (org.graalvm.polyglot.Context) からゲスト言語を実行する • ゲスト言語の関数を実行する • ゲスト言語の変数 (オブジェクト) にアクセスする • ゲスト言語から ホスト環境の Java オブジェクトにアクセスする • ゲスト言語から Java クラスにアクセスする Java にポリグロット言語を埋め込む (Embedding) 主な機能 Context context = Context.create(); context.eval("js", "print('Hello JavaScript!');"); Value function = context.eval("js", "x => x+1"); int x = function.execute(41).asInt(); // 42 context.getBindings("js").putMember("javaObj", new BigDecimal(3)); context.eval("js", "print(javaObj.pow(2));"); // 9 Value result = context.eval("js", "({array: [1,2,8,16]})"); int v = result.getMember("array").getArrayElement(2).asInt(); // 8 Context context = Context.newBuilder().allowAllAccess(true).build(); context.eval("js", "Java.type('java.lang.System').out.println('Hello World!');");
  39. Copyright © 2022, Oracle and/or its affiliates 46 起動方法 •

    $JAVA_HOME/bin/js --polyglot --jvm <JavaScriptファイル名> Java を呼び出す • 前頁のとおり、Java.type(クラス名) を使う 他の言語を呼び出す • Polyglot.eval(“<ゲスト言語>”, “<ゲスト言語で書かれたスクリプト>") 言語ランタイムから他の言語を呼び出す JavaScript の例 var array = Polyglot.eval("python", "[1,2,42,4]"); // array print(array[2]); // 42 var datetime = Polyglot.eval("python", "import datetime¥ndatetime.datetime"); // type print(datetime.now().isoformat()); var now = Polyglot.eval("python", "import datetime¥ndatetime.datetime.now()"); // object print(now.isoformat()); JavaScript から Python を呼び出す import datetime datetime.datetime import datetime datetime.datetime.now()
  40. Copyright © 2022, Oracle and/or its affiliates 47 Rhino, Nashorn

    の代替 • GraalVMに は互換性のための起動オプションあり JVMのスレッドプールを使ったマルチスレッド実行 • ワーカースレッドにポリグロット・コンテキストを割り当てる • ロシアの大手SNSで、JS (React) を使った HTML レンダリング処理をサーバーサイドで実行した例 https://prog.world/new-odnoklassniki-frontend-launching-react-in-java-part-i/ 他の GraalVM 言語 (Java, Ruby, Python, LLVM, R, etc.) とデータとコードを共有 • npm ライブラリでは未提供の機能を Java ライブラリで代替するなどの活用法が考えられる • Neo4J の Java ライブラリを色々な言語から使ってみた例 https://github.com/michael-simons/neo4j-graalvm-polyglot-examples/ GraalVM ツールのサポート - Insight, VisualVM, Chrome Debugger, VS Code extensions, etc. • Node.js アプリケーション に Java/GraalVM エコシステムの恩恵を与えることができる JavaScript/Node.js with GraalVM GraalVM で JavaScript コードを実行する積極的理由を考えてみた
  41. Copyright © 2022, Oracle and/or its affiliates 48 プログラムのランタイム動作をトレースして、情報を取得したり、処理を記述したりするためのツール •

    実行プログラムとは別にプログラム (polyglot対応) を記述して、実行時にアタッチする • $JAVA_HOME/bin/node --insight=<Insightプログラム> <アプリケーション.js> • 設定したトレースポイント (‘source’, ‘enter’, ‘return’, ‘close’) のイベントでの処理を記述 • 変数の参照 • 変数の値の変更 • 例外の送出 • メソッドのインターセプト • 実行スタックの参照 • ヒープダンプの取得 GraalVM Insight https://www.graalvm.org/tools/graalvm-insight API (Javadoc でちょっと分かりにくい…) https://www.graalvm.org/tools/javadoc/org/graalvm/tools/insight/Insight.html 実行アプリ Insight プログラム GraalVM アタッチ --insight insight.on('enter', function(ev) { var cnt = map.get(ev.name); ... }, { roots: true });
  42. Copyright © 2022, Oracle and/or its affiliates 49 • Chrome

    DevTools Protocol の組込み実装を提供 • Chrome Developer Toolsなどの互換性のあるデバッガをGraalVMにアタッチできる Chrome デバッガ ゲスト言語アプリケーションのデバッグ >c:¥opt¥java¥graalvm-ee-java11-22.2.0¥bin¥node --jvm --inspect server.js Debugger listening on ws://127.0.0.1:9229/x1N0pf3jcy7y9BOW4oB2wnr1AH2Pqyg48cy63uInp7Q For help, see: https://www.graalvm.org/tools/chrome-debugger E.g. in Chrome open: devtools://devtools/bundled/js_app.html?ws=127.0.0.1:9229/x1N0pf3jcy7y9BOW4oB2wnr1AH2Pqyg48cy63uInp7Q ブレークポイント ステップ実行 変数の参照 etc.
  43. Copyright © 2022, Oracle and/or its affiliates 50 GraalVM に関するサポートを追加

    • 実行中の GraalVM プロセスの監視 • ネイティブ イメージ プロセスの基本的な監視 • ゲスト言語レベルでのアプリケーションの分析 (Graal Sampler、Heap Viewer) • JavaScript、Python、Ruby、R 言語をサポート Graal VisualVM All-in-One Java Troubleshooting Tool
  44. Copyright © 2022, Oracle and/or its affiliates 51 デモ:Node.js on

    GraalVM Node.js アプリケーションを Insight で実行状況を確認する Node.js アプリケーションを Chrome デバッガでデバッグする Node.js アプリケーションを VisualVM でモニタ/プロファイルする Virtual Machine Autonomous Database Key Vault VisualVM GraalVM Node.js App モニタ/プロファイル GraalVM Node.js App Chrome デバッグ GraalVM Node.js App Insight Insight
  45. Copyright © 2022, Oracle and/or its affiliates 53 GraalVMの基本機能 •

    GraalVM JIT Compiler, AOT Compiler, Truffle ネイティブ・イメージ作成のためのツール群 • ネイティブ・イメージ ビルダー • トレース・エージェント • Maven プラグイン, Gradle プラグイン ネイティブ・イメージ作成に対応したフレームワーク • Helidon, Micronaut, Spring Native, Quarkus, ... • OCI Functions FDK でネイティブ・イメージを作成 ポリグロット機能と開発支援ツール • Insight, Debugger, VisualVM まとめ 最初に登場した頃に比べて 各段に使いやすくなっているので 過去一度幻滅?した方も含めて 是非最新版の GraalVM を 試してもらいたいです!
  46. Copyright © 2022, Oracle and/or its affiliates 54 ドキュメンテーション •

    GraalVM https://www.graalvm.org/docs/ • Oracle GraalVM Enterprise Edition 日本語ドキュメンテーション https://docs.oracle.com/cd/F44923_01/index.html • Helidon AOT https://helidon.io/docs/v3/#/se/aot https://helidon.io/docs/v3/#/mp/aot • Micronaut https://docs.micronaut.io/ 記事 • Javaに革命を起こすGraalVM Native Image https://www.infoq.com/jp/articles/native-java-graalvm/ • Micronautフレームワークを使ったクラウドネイティブJava https://www.infoq.com/jp/articles/native-java-micronaut/ デモ・ソース • GitHub https://github.com/oracle-japan/ochacafe-graalvm 参考資料