Java 8 ランタイム環境

App Engine を使用すると、Google のスケーラブルなインフラストラクチャとサービスを使用するウェブ アプリケーションを構築できます。App Engine は、Java 8 JVM を使用して、ウェブ アプリケーションを実行します。App Engine は、アプリのサーブレット クラスを呼び出して、この環境でリクエストの処理とレスポンスの準備を行います。

App Engine プラットフォームには、コードから呼び出せる多数の組み込み API サービスが用意されています。また、アプリケーションでは、指定の間隔で実行されるタスクのスケジュールを構成することもできます。

アプリ用の Java 8 ランタイムの指定

アプリに Java 8 ランタイムを使用するには、次の行を appengine-web.xml ファイルに追加します。

<runtime>java8</runtime>

このように変更するだけで、以前 Java 7 ランタイムを使用していた既存の App Engine アプリケーションは、Java 8 ランタイムで実行されるようになります。

App Engine API for Java は、Google Cloud CLI の一部として App Engine SDK に付属する appengine-api-*.jar で表されます(ここで、* は API と App Engine SDK のバージョンを表します)。

アプリケーションで使用する API のバージョンを選択するには、この JAR をアプリケーションの WEB-INF/lib/ ディレクトリに配置するか、Maven を使用して依存関係を処理します。リリースされた新しいバージョンの Java ランタイム環境に、既存のアプリと互換性のない変更が導入された場合、この環境には新しいバージョン番号が付与されます。

Maven を使用して依存関係を処理する

Maven を使用してすべての依存関係を管理できます。たとえば、以下の pom.xml エントリには、Maven Central で入手可能な最新の App Engine API(Rappengine-api-1.0-sdk)が含まれています。

<dependency>
    <groupId>com.google.appengine</groupId>
    <artifactId>appengine-api-1.0-sdk</artifactId>
    <version>1.9.98</version>
</dependency>

サンドボックス

App Engine Java ランタイムは、複数のアプリケーションへのリクエストを複数のウェブサーバーに分散し、アプリケーションが相互に干渉しないようにします。App Engine アプリのレスポンスが遅くならないようにする必要があります。アプリケーションへのウェブ リクエストは、リクエストのタイムアウト上限以内に処理される必要があります。レスポンス時間がこの上限を超えるプロセスは、ウェブサーバーの過負荷を防ぐために終了します。

ユーザーがファイルを書き込むことができる場所は /tmp ディレクトリのみです。/tmp 内のファイルは、インスタンスに割り当てられたメモリを消費します。この場所に格納されているファイルは、このインスタンスでのみ使用でき、この特定のインスタンスの存続期間中のみ使用できます。

アプリケーションがリソース ファイルを取得する通常の方法は、WEB-INF の下でアプリケーションで依存するファイルをパッケージ化し、Class.getResource()ServletContext.getResource()、または同様の方法でアプリから読み込むことです。デフォルトでは、WAR に含まれるすべてのファイルは「リソース ファイル」です。このセットからファイルを除外するには、appengine-web.xml ファイルを使用します。

クラスローダーでの JAR の順序付け

クラス名の衝突を解決するために、JAR ファイルをスキャンしてクラスを検索する順序を定義し直す必要が生じることがあります。このような場合は、appengine-web.xml ファイルに <priority-specifier> 要素を含む <class-loader-config> 要素を追加して、特定の JAR ファイルが優先的に読み込まれるようにできます。次に例を示します。

<class-loader-config>
  <priority-specifier filename="mailapi.jar"/>
</class-loader-config>

このようにすると、war/WEB-INF/classes/ ディレクトリ内の JAR ファイルではなく「mailapi.jar」が、クラスを検索する最初の JAR ファイルになります。

複数の JAR ファイルが優先されている場合は、元の読み込み順序(互いに対する順序)が使用されます。つまり、<priority-specifier> 要素自体の順序は関係ありません。

スレッド

Java 8 ランタイムでは、App Engine の ThreadManager API と Java の組み込み API(new Thread() など)を使用して、スレッドを作成できます。現在、App Engine API(com.google.appengine.api.*)を呼び出す場合は、リクエスト スレッドまたは ThreadManager API を使用して作成されたスレッドからそれらの API を呼び出す必要があります。

アプリケーションでは次のことが可能です。

currentRequestThreadFactory()ThreadPoolExecutor を作成する場合、サーブレット リクエストが完了する前に shutdown() を明示的に呼び出す必要があります。これを行わないと、リクエストが完了せず、最終的にアプリサーバーで障害が発生します。一部のライブラリで ThreadPoolExecutor が作成される場合があるので注意してください。

アプリケーションは、現在のスレッドに対して thread.interrupt() のようなオペレーションを実行できます。

各リクエストは、50 の同時実行 App Engine API リクエスト スレッドに制限されます。

スレッドを使用する場合は、ExecutorRunnable などの高レベル同時実行オブジェクトを使用します。これらのオブジェクトは、割り込みスケジュールと記帳のような、細かいながらも重要な同時実行の詳細の多くを処理します。

App Engine API で作成される同時実行バックグランド スレッドの最大数はインスタンスごとに 10 個です(この上限は App Engine API とは関係のない、通常の Java スレッドには適用されません)。

ツール

サポートされている IDE

Cloud Tools for Eclipse を導入すると、Eclipse IDE に、App Engine プロジェクト用の新しいプロジェクト ウィザードとデバッグ構成が追加されます。App Engine プロジェクトを Eclipse 内からライブで本番環境にデプロイできます。

Cloud Tools for IntelliJ を使用すると、IntelliJ IDEA 内で App Engine アプリケーションを実行してデバッグできます。IDE を閉じることなく、App Engine プロジェクトをライブで本番環境にデプロイできます。

サポートされているビルドツール

開発プロセスを高速化するには、Apache Maven または Gradle 用の App Engine プラグインを使用できます。

ローカルの開発用サーバー

開発用サーバーを使用すると、アプリケーションの開発とテストのために、ローカルのコンピュータ上でアプリケーションを実行できます。サーバーは Datastore サービスをシミュレートします。また、開発用サーバーでは、テスト中にアプリが実行するクエリに基づいて、Datastore インデックスの構成を生成することもできます。

同時実行とレイテンシ

トラフィックに対処するために必要なインスタンスの数に特に大きく影響するのはアプリケーションのレイテンシです。リクエストを短時間のうちに処理できるサービスであれば、1 つのインスタンスで多くのリクエストを処理できます。

シングル スレッドのインスタンスでは、同時に 1 件のリクエストしか処理できません。そのため、レイテンシと、インスタンスで処理できる 1 秒あたりのリクエスト数の間には直接的な相関関係があります。たとえば、10 ミリ秒のレイテンシでは、1 つのインスタンスで 1 秒間に 100 件のリクエストを処理します。

マルチスレッドのインスタンスでは、多数のリクエストの同時処理が可能です。そのため、CPU 使用量と 1 秒あたりのリクエスト処理数の間に直接の相関関係があります。

Java アプリは、同時リクエストをサポートしているため、1 つのインスタンスで他のリクエストが完了するまで待機している間に、新しいリクエストを処理できます。同時実行性を使用すると、アプリが必要とするインスタンスの数が大幅に少なくなりますが、アプリをマルチスレッド対応として設計する必要があります。

たとえば、B4 インスタンス(約 2.4 GHz)がリクエスト 1 件につき 10 M サイクルを使用する場合、1 つのインスタンスでの 1 秒あたりのリクエスト処理数は 240 件になります。リクエスト 1 件につき 100 M サイクルを使用する場合は、1 つのインスタンスでの 1 秒あたりのリクエスト処理数は 24 件になります。このような数字は理想的な条件を想定したものですが、インスタンスの処理能力という点ではかなり現実的な数字です。

App Engine Java のリリース

バージョン 2.x.x 以降のすべてのリリース済みアーティファクトでは、オープンソースのリリース メカニズムを使用します。バージョン 1.9.9xx 以前のリリース済みアーティファクトでは、内部ビルドシステムを使用します。詳細については GitHub リポジトリをご覧ください。

環境変数

ランタイムは以下の環境変数を設定します。

環境変数 説明
GAE_APPLICATION App Engine アプリケーションの ID。この ID の先頭には「region code~」が付きます。たとえば、ヨーロッパでデプロイされたアプリケーションの場合は「e~」となります。
GAE_DEPLOYMENT_ID 現在のデプロイの ID。
GAE_ENV App Engine の環境。standard に設定します。
GAE_INSTANCE 現在サービスが実行されているインスタンスの ID。
GAE_RUNTIME app.yaml ファイル内で指定したランタイム。
GAE_SERVICE app.yaml ファイル内で指定したサービス名。サービス名が指定されていない場合は、default に設定されます。
GAE_VERSION サービスの現在のバージョン ラベル。
GOOGLE_CLOUD_PROJECT アプリケーションに関連付けられた Cloud プロジェクト ID。
PORT HTTP リクエストを受信するポート。

app.yaml ファイル内で追加の環境変数を定義できますが、上記の値をオーバーライドすることはできません。