ノート:

GraalVM EnterpriseでOracle Cloudのアプリケーションを高速化

イントロダクション

GraalVM Enterpriseは高パフォーマンスのJDKディストリビューションで、信頼性が高く安全なOracle Java SE上に構築されています。これにより、アプリケーションの実行と効率が大幅に改善されます。

GraalVM EnterpriseはOracle Java SE Subscriptionに含まれ、Oracle Cloud Infrastructure(OCI)に無料で利用可能

GraalVM Enterpriseは、Javaアプリケーションを実行するための2つの方法を提供します。HotSpot JVM、または事前にコンパイルされたネイティブ・エクセクト可能。HotSpot JVMで実行すると、GraalVM EnterpriseはGraalコンパイラを最上位JITコンパイラとして使用します。コンパイラは高度な最適化を実行し、積極的なインライン化手法を適用して、コードを変更せずにアプリケーションのパフォーマンスを高速化します。ネイティブのExectuable GraalVM Enterpriseで実行すると、ネイティブ・イメージを使用して、Javaアプリケーションを、JVMの実行、即時起動およびウォームアップ時間なしでピーク・パフォーマンスを提供する自己完結型ネイティブ実行可能ファイルに変換します。

この演習では、JVMのデモ・プロジェクトを実行し、ネイティブのExectuablesとしてパフォーマンスを比較して、GraalVM EnterpriseでOCI上のアプリケーションをどのように高速化できるかをご覧ください。リソース要件の低いアプリケーションをより高速にすると、サーバー数が少なくなるか小さくなるため、クラウド・コストが削減されます。

ラボ・コンテンツ

この演習では、次のことを行います。

予想実習時間: 30分

注:ラップトップアイコンが表示された場合は常に、コマンドの入力やファイルの編集などのアクションを実行する必要があります。

# The box under the icon will tell you what to do.

コマンドをコピーするには、フィールドの上にカーソルを置き、「クリップボードにコピー」アイコンをクリックします。

端末ウィンドウでコピーしたコマンドを貼り付けるには、右クリックしてコンテキスト・メニューからPasteオプションを選択します。かわりにキーボード・ショートカットを使用する場合は、CTRL+SHIFT+Vを使用します。

タスク1: Oracle CloudのVMインスタンスへの接続

演習を開始すると、必要なリソースがバックグラウンドでプロビジョニングされます:仮想クラウド・ネットワーク(VCN)、コンピュート・インスタンスにはOracle Linux 8の事前構築済イメージが含まれます。リソースのプロビジョニングには、ネイティブ・イメージを使用したGraalVM Enterpriseランタイム環境のインストールおよび構成も含まれており、このラボの簡潔さを維持して時間を節約できます。プロビジョニングの完了には約5分かかる場合があります。「Luna Lab」Webページの「Resources」タブを参照すると、リソースが完全にプロビジョニングされ、準備ができたときにわかります(次の手順1を参照)。

  1. デスクトップの「Luna Lab」アイコンをダブルクリックしてブラウザを開きます。

    「リソース」以外のアニメーション・ギアがチェック・マークになるまで待ちます。つまり、必要なすべてのコンピュートおよびネットワーク・リソースがプロビジョニングされ、続行できます。

  2. Luna Labページの「リソース」タブをクリックします。「リソース」ページには、プロビジョニングされたVMインスタンスの名前とパブリックIPアドレスが表示されます。

  3. SERVER_IPボックスからパブリックIPアドレスをコピーします。多くのユーザーがView Detailsをクリックする必要があります。フィールドの上にカーソルを置いてから、クリップボードにコピー・アイコンをクリックします。

  4. Lunaデスクトップが表示されるように、ブラウザ・ウィンドウを最小化します。「アプリケーション」メニューをクリックし、ターミナル・エミュレータを開きます。

  5. SSH接続コマンドを入力します。はVMインスタンスのパブリックIPアドレスです:

    ssh opc@<SERVER_IP>
    

    プロンプトで yesと入力して、ECDSA鍵のフィンガープリントを受け入れます。

これで、Oracle CloudのVMインスタンスに接続しました。VMインスタンスは、この演習に必要なGraalVM Enterpriseおよびネイティブ・イメージ・ツールで事前構成されています。次のコマンドを実行して、簡単に確認できます。

java -version

native-image --version

GraalVM Enterpriseとその機能をお客様自身でOracle Linuxにインストールする方法を学習するには、この演習の完了時にGraalVMスタート・ガイドのラボを実行してください。

次のタスクに進むことができます。

タスク2:デモの実行: Java Microbenchmark Harness (JMH)

この部では、Javaベンチマークを実行して、GraalVM Enterprise JITコンパイラとC2 JITコンパイラのパフォーマンスを比較します。GraalVM Enterpriseでデフォルトで有効になっているGraalコンパイラは、コード分析、高度な最適化、およびディープ・クラス階層とワイド・クラス階層のための非常に積極的なインライン化アルゴリズムの実行を通じて、JVMで実行されるプログラムに対して最適化されたパフォーマンスを提供します。

実行するベンチマークは、Java Microbenchmark Harness (JMH)で記述され、Java Stream APIを使用します。これは、コンパイラが連携して実行するインライン化および部分エスケープ分析を示しており、実行時に大幅なパフォーマンス向上について説明します。

デモ・ソース・コードは、java-simple-stream-benchmarkディレクトリにあります。

マイクロ・ベンチマークでは、配列要素からストリームを作成し、複数のマッピング関数を使用して各数をマップします。

public class JavaSimpleStreamBenchmark {

  static int[] values = new int[]{1, 2, 3, 4, 5, 6, 7, 8, 9, 10};

  @Benchmark
  public int testMethod() {
    return Arrays.stream(values)
      .map(x -> x + 1)
      .map(x -> x * 2)
      .map(x -> x + 2)
      .reduce(0, Integer::sum);
  }
}

JavaSimpleStreamBenchmark.testMethodは3回の反復で実行され、JITコンパイラがパフォーマンスをサンプリングする前にウォームアップできます。ベンチマーク結果はコンソールに出力され、1操作あたりナノ秒であり、数値が小さいほど優れています。

  1. VMインスタンスに接続された端末ウィンドウで、demoディレクトリに移動します。

    cd java-simple-stream-benchmark
    
  2. ベンチマーク・プロジェクトはMavenを使用して構築されていますが、Mavenラッパー(.mvnw)には付属しておらず、Oracle LinuxにはデフォルトでMavenが含まれていません。yumを使用してMavenをインストールします。

    sudo yum install maven
    
  3. プロジェクトを作成します。

    mvn package
    
  4. GraalVM Enterprise JITコンパイラでベンチマークを実行します。

    java -jar target/benchmarks.jar
    

    javaコマンドを呼び出すことで、GraalVM Enterpriseでデフォルトで有効な最適化されたGraal JITコンパイラを使用します。

  5. 同じJVM (GraalVM Enterprise)でベンチマークを実行しますが、-XX:-UseJVMCICompilerオプションを適用して、GraalコンパイラではなくC2コンパイラを使用します。

    java -XX:-UseJVMCICompiler -jar target/benchmarks.jar
    

ステップ4-5を完了した後にベンチマーク結果を比較します。結果は、VMインスタンスのプロセッサ数およびメモリーによって異なります。VM.Standard.2-2シェイプおよび30GBのメモリーでコンピュート・インスタンスで使用される数は次のとおりです:

Graal JITコンパイラ:

[opc@demo-instance java-simple-stream-benchmark]$ java -jar target/benchmarks.jar
...
Benchmark                             Mode  Cnt   Score    Error  Units
JavaSimpleStreamBenchmark.testMethod  avgt    3  53.474 ? 1236.199  ns/op

C2 JITコンパイラ:

[opc@demo-instance java-simple-stream-benchmark]$ java -XX:-UseJVMCICompiler -jar target/benchmarks.jar
...
Benchmark                             Mode  Cnt    Score    Error  Units
JavaSimpleStreamBenchmark.testMethod  avgt    3  361.844 ? 37.120  ns/op

Graal JITコンパイラの平均結果は、同じベンチマークでC2よりも5倍高速です。

次のタスクに進むことができます。

タスク3:デモの実行: Micronaut Native Linux実行可能ファイル

このタスクでは、JVMでJavaマイクロサービスを実行したときの起動時間およびネイティブ実行可能ファイルとして比較します。いずれの場合も、マイクロサービスはGraalVM Enterpriseで実行されますが、開始の急増を示すために、ジャストインタイムやコンパイル後の様々なモードで実行されます。

このマイクロサービスは、マイクロサービスやサーバーレス・アプリケーションの構築に最適なフルスタックのJavaフレームワークであるMicronautで記述されています。これは、単純なサーバー・サイド・レンダリング・アプリケーションであり、サービスConferenceService.javaには会議のリストが含まれ、ランダムな会議が返されます。コントローラは、@Controller注釈を使用して定義され、ランダムな会議名を取得するためにパス/conferencesにマップされます。Micronautは、レスポンスで自動的にJSONに変換します。

  1. ホーム・ディレクトリに戻ります。

    cd
    
  2. MavenまたはGradleビルド・ツールを指定するMicronautアプリケーションを作成し、アプリケーション・ソースをダウンロードし、アーカイブを解凍してナビゲートします。

    mkdir micronaut-demo && cd micronaut-demo
    

    Maven:

    curl https://guides.micronaut.io/latest/micronaut-creating-first-graal-app-maven-java.zip -o micronaut-creating-first-graal-app.zip
    

    Gradle:

    curl https://guides.micronaut.io/latest/micronaut-creating-first-graal-app-gradle-java.zip -o micronaut-creating-first-graal-app.zip
    

    Micronautの3.0.xバージョンをダウンロードします。

    unzip micronaut-creating-first-graal-app.zip
    
  3. JVM (GraalVM Enterprise)上でGradleまたはMavenラッパーを使用してアプリケーションをビルドおよび実行します。

    Maven:

    ./mvnw mn:run
    

    Gradle:

    ./gradlew run
    

    アプリケーションがポート8080で起動されます。この単純なMicronautマイクロサービスの開始に要した時間に注意してください。

    JITでシンプルなMicronautマイクロサービスを開始するのにかかる時間を見る

  4. CTRL+Cを入力してアプリケーションを終了します。

  5. ネイティブ・イメージでスタンドアロンのネイティブLinux実行可能ファイルを生成します。GradleまたはMavenを使用してネイティブ実行可能ファイルを構築できます。

    native-imageパッケージ形式を指定してMavenを使用する場合:

    ./mvnw package -Dpackaging=native-image
    

    MicronautプロジェクトのnativeImageタスクの実行によるグラード:

    ./gradlew nativeImage
    

    Mavenを使用した場合、micronautguideという実行可能ファイルはデフォルトでプロジェクトのtarget/ディレクトリに書き込まれ、またはGradleを使用した場合はapplicationというbuild/native-image/ディレクトリに書き込まれます。

    ノート:実行可能ファイルを構築する時間は、アプリケーションのサイズと複雑さによって異なりますが、低電力のVMでは時間がかかる場合があります。

  6. 実行可能ファイルを起動します。

    Mavenとともに構築:

    ./target/micronautguide
    

    Gradleを使用して構築:

    ./build/native-image/application
    

    もう一度、このマイクロサービスを開始するのに要した時間をネイティブ実行可能ファイルとしてメモします。実行可能ファイルが自己完結型バイナリであり、JDKを実行する必要がなく、アプリケーションを簡単に配布できるため、はるかに速く開始されます。ファイルサイズもかなり小さくなります。

    ネイティブ実行可能ファイルとそのファイル・サイズからMicronautマイクロサービスを起動するのに要した時間を確認

  7. CTRL+Cを入力してアプリケーションを終了します。

GraalVM Native Imageは、アプリケーション・クラス、依存ライブラリ・クラス、依存JDKクラス、およびアプリケーション・ヒープのスナップショット(構築時に初期化されるクラス)を含むネイティブ実行可能ファイルを作成します。ネイティブ実行可能ファイルとしてJavaアプリケーションを実行すると、即時起動、CPUとメモリー消費の削減が可能になり、GraalVM Enterpriseランタイム環境はクラウド・デプロイメントの適正な候補となります。

すでに起動時間の違いが見られており、すでにこのラボを終了できます。ただし、VMインスタンスへのトラフィックを許可するようにホスト・ファイアウォールを構成する必要があるブラウザで実行中のこのサーバー側アプリケーションを続行してテストできます。タスク4に進みます。

タスク4: VMインスタンスへのトラフィックを許可するホスト・ファイアウォールの構成(オプション)

前述のサーバー側アプリケーションをブラウザでテストするには、ホスト・ファイアウォールで仮想マシンへのトラフィックが許可されていることを確認する必要があります。

  1. OCIコンソールにログインします。Luna Labページを開き、OCIコンソールのクイック・リンクをクリックします。この演習エフェメラル・アカウントの「資格証明」で指定したユーザー名とパスワードを入力します。

  2. OCIコンソールにログインしたら、「コンピュート」に移動して「インスタンス」をクリックします。

    コンピュート・インスタンスの検索

  3. 左側の「コンパートメント」ドロップダウンで必要なコンパートメントを選択します。コンパートメント名を検索するには、「Luna Lab」ページに戻り、「Oracle Cloud」をクリックして、「コンパートメント名」フィールドを参照してください。

  4. メイン・ビューでVMインスタンスを見つけて開きます。

  5. 「プライマリVNIC」セクションで、インスタンスがアタッチされている「サブネット」をクリックします。

  6. サブネット・ページで、セキュリティ・リスト(ds-luna-seclist-で始まる名前)をクリックします。

  7. 「イングレス・ルールの追加」を押して、次のデータを入力します:

    ポートへの受信トラフィックを許可するイングレス・ルールの追加

    この規則により、すべてのソースからのトラフィックがポート 8080を使用できるようになり、アプリケーションがどこからでも到達できるようになります。

  8. 端末ウィンドウに戻り、次のコマンドを実行して、実行中のVMインスタンスでファイアウォールを再起動します。

    sudo firewall-cmd --permanent --add-port=8080/tcp
    

    sudo systemctl reload firewalld
    
  9. アプリケーションを再起動します。

    Mavenとともに構築:

    ./target/micronautguide
    

    Gradleを使用して構築:

    ./build/native-image/application
    
  10. ブラウザhttp://<SERVER_IP>:8080/conferences/randomでアプリケーションを開きます。ここで、<SERVER_IP>はインスタンスのパブリックIPアドレスです。Micronautの@Controller注釈は/conferencesパスにマップされているため、/conferences/randomパスをURLに追加する必要があります。

    http://<SERVER_IP>:8080/conferences/random
    
  11. (オプション)新しい用語ウィンドウを開き、curlを使用してGETリクエストを送信します:

    curl http://<SERVER_IP>:8080/conferences/random
    

完了しました。この演習を正常に完了している。

さらに学ぶ

このセッションを終了するには、ツールバーの「End Session」ボタンをクリックします。

その他の学習リソース

docs.oracle.com/learnの他のラボを調べるか、Oracle Learning YouTubeチャネルでさらに無料の学習コンテンツにアクセスします。さらに、education.oracle.com/learning-explorerにアクセスしてOracle Learning Explorerにします。

製品ドキュメントは、Oracleヘルプ・センターを参照してください。