App Engine を使用すると、Google のスケーラブルなインフラストラクチャとサービスを使用するウェブ アプリケーションを構築できます。App Engine は、Java 8 JVM を使用して、ウェブ アプリケーションを実行します。App Engine は、アプリのサーブレット クラスを呼び出して、この環境でリクエストの処理とレスポンスの準備を行います。
App Engine プラットフォームには、コードから呼び出せる多数の組み込み API サービスが用意されています。また、アプリケーションでは、指定の間隔で実行されるタスクのスケジュールを構成することもできます。
アプリ用の Java 8 ランタイムの指定
アプリに Java 8 ランタイムを使用するには、次の行を appengine-web.xml
ファイルに追加します。
<runtime>java8</runtime>
platform/google_appengine/google/appengine/tools/java/lib/impl/appengine-api.jar
の下にある Google Cloud CLI の appengine-api.jar
ファイルは、App Engine API for Java を表します。すべてのバージョンを一覧表示する Maven リポジトリを使用して、このファイルにアクセスすることもできます。
アプリケーションで使用する API のバージョンを選択するには、この JAR をアプリケーションの WEB-INF/lib/
ディレクトリに配置するか、Maven を使用して依存関係を処理します。リリースされた新しいバージョンの Java runtime environment に、既存のアプリと互換性のない変更が導入された場合、この環境には新しいバージョン番号が付与されます。
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></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 を呼び出す必要があります。
アプリケーションでは次のことが可能です。
java.lang.Runnable
を実装する。com.google.appengine.api.ThreadManager.currentRequestThreadFactory()
を呼び出してスレッド ファクトリを作成する。- ファクトリーの
newRequestThread
メソッドを呼び出してRunnable
、newRequestThread(runnable)
を渡すか、ExecutorService
(たとえば、Executors.newCachedThreadPool(factory)
呼び出し)を使ってcom.google.appengine.api.ThreadManager.currentRequestThreadFactory()
によって返されたファクトリ オブジェクトを使用する。
currentRequestThreadFactory()
で ThreadPoolExecutor
を作成する場合、サーブレット リクエストが完了する前に shutdown()
を明示的に呼び出す必要があります。これを行わないと、リクエストが完了せず、最終的にアプリサーバーで障害が発生します。一部のライブラリで ThreadPoolExecutor が作成される場合があるので注意してください。
アプリケーションは、現在のスレッドに対して thread.interrupt()
のようなオペレーションを実行できます。
各リクエストは、50 の同時実行 App Engine API リクエスト スレッドに制限されます。
スレッドを使用する場合は、Executor
や Runnable
などの高レベル同時実行オブジェクトを使用します。これらのオブジェクトは、割り込みやスケジュールと記帳のような、細かいながらも重要な同時実行の詳細の多くを処理します。
ツール
サポートされている IDE
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 |
アプリケーションに関連付けられた Google Cloud プロジェクト ID。 |
PORT |
HTTP リクエストを受信するポート。 |
app.yaml
ファイル内で追加の環境変数を定義できますが、上記の値をオーバーライドすることはできません。