ウォームアップ リクエストを構成してパフォーマンスを改善する

新たに作成されたインスタンスにアプリのコードが読み込まれる際のリクエストとレスポンスのレイテンシを短縮するには、ウォームアップ リクエストを使用します。

App Engine は、作成されたばかりのインスタンスにアプリのコードを頻繁に読み込む必要があります。次の場合にインスタンスの読み込みが起こる可能性があります。

  • 別のバージョンのアプリを再デプロイするとき。
  • リクエスト数が現在実行中のインスタンス セットの容量を超え、その不足分を補うために新しいインスタンスが作成されるとき。
  • 基盤となるインフラストラクチャやハードウェアのメンテナンスまたは修復が行われるとき。

アプリのコードを新しいインスタンスに読み込むと、読み込みリクエストが発生することがあります。読み込みリクエストのために、ユーザーのリクエスト レイテンシが増加する可能性がありますが、ウォームアップ リクエストを使用することによりこのレイテンシを回避できます。ウォームアップ リクエストは、実際のリクエストがインスタンスに到達するよりも先にアプリのコードを新しいインスタンスに読み込みます。

アプリケーションでウォームアップ リクエストが有効化されていると、App Engine は新しいインスタンスがアプリケーションで必要になるタイミングを検知し、ウォームアップ リクエストを開始して新しいインスタンスを初期化しようとします。しかし、この検出がいつもうまくいくとは限りません。そのため、アプリでウォームアップ リクエストが有効になっていても、読み込みリクエストが発生する場合があります。たとえば、アプリがトラフィックを処理していなければ、アプリへの最初のリクエストはウォームアップ リクエストではなく、常に読み込みリクエストになります。

App Engine アプリケーションに対する他のリクエストと同様、ウォームアップ リクエストもインスタンス時間を消費します。ウォームアップ リクエストが有効になっていても、読み込みリクエストの代わりにウォームアップ リクエストでアプリケーションの初期化が行われているだけなので、ほとんどの場合インスタンス時間が増えていることには気づきません。ウォームアップ リクエスト中に事前キャッシングなどの他の処理も行うと、インスタンス時間が増える可能性があります。min_idle_instances0 より大きい値に設定すると、それらのインスタンスの初回起動時にウォームアップ リクエストが発生する可能性がありますが、それ以降も使用できます。

デフォルトのウォームアップ リクエストでは、すべての JAR ファイルがメモリ内のインデックスに登録され、アプリケーションとフィルタが初期化されます。

ウォームアップ リクエストを有効にする

ウォームアップ リクエストは、App Engine スケジューラによって使用されます。このスケジューラはユーザーが指定した構成に基づいてインスタンスの自動スケーリングを制御します。App Engine の Java ランタイムでは、ウォームアップ リクエストがデフォルトで有効になっているため、App Engine が /_ah/warmup に対して GET リクエストを発行することで、必要に応じてレスポンスを返し、アプリケーションのコードを初期化できます。ウォームアップ リクエストは、次のいずれかの方法で処理できます。

<load-on-startup> サーブレットの使用
ウォームアップ ロジックを追加する最も簡単な方法は、web.xml 構成ファイルで独自のサーブレットを <load-on-startup> として指定する方法です。
ServletContextListener の使用
ウォームアップ リクエストまたは読み込みリクエストでサーブレットが最初に呼び出される前に、カスタム ロジックを実行できます。
カスタム ウォームアップ サーブレットを使用する
カスタム ウォームアップ サーブレットを使用すると、読み込みリクエストの処理時ではなくウォームアップ リクエストの処理時にのみ、サーブレットの service メソッドが呼び出されます。

選択した方法によっては、/_ah/warmup に独自のハンドラを実装する必要があります。

始める前に

ウォームアップ リクエストが有効になっている場合、さらに多くのインスタンスが必要であると判断すると、スケジューラはインスタンスを起動します。スケジューラはウォームアップ リクエストを使用してアプリを起動するため、アプリでそのリクエストが処理されていなくても、ログには表示されます。

次のメッセージは、/_ah/warmup ログのウォームアップ リクエストを示しています。

This request caused a new process to be started for your application, and thus caused your application code to be loaded for the first time. This request may thus take longer and use more CPU than a typical request for your application.

ウォームアップ リクエストは必ず呼び出されるとは限りません。代わりに読み込みリクエストが送信されることがあります。たとえば、インスタンスが初めて起動されるインスタンスである場合や、トラフィックが急激に上昇する場合です。ただし、ウォームアップ リクエストが有効になっている場合は、すでにウォームアップされているインスタンスにリクエストを送信する「ベスト エフォート方式」が試行されます。

Java 8 では、ウォームアップ リクエストがデフォルトで有効になっています。有効にするには、appengine-web.xmlinbound_services ディレクティブに - warmup を追加します。ウォームアップはデフォルトで有効になるため、明示的に有効にする必要があるのは、appengine-web.xml でウォームアップ リクエストを無効にしてアプリケーションをデプロイした場合に限られます。この場合は、<warmup-requests-enabled> の値を true に設定してから再デプロイする必要があります。

<load-on-startup> サーブレットの使用

ウォームアップ ロジックを追加する最も簡単な方法は、web.xml で独自のサーブレットを <load-on-startup> として指定する方法です。この方法の場合、アプリケーション コードを変更する必要がなく、アプリケーションで初期化するときに、指定したすべてのサーブレットが初期化されます。

web.xml ファイルで、起動時に読み込むサーブレットの <servlet> 要素に <load-on-startup>1</load-on-startup> 要素を追加します。例:

<servlet>
  <servlet-name>my-servlet</servlet-name>
  <servlet-class>com.company.MyServlet</servlet-class>
  <load-on-startup>1</load-on-startup>
</servlet>

このコードでは、指定したサーブレット クラスを読み込み、サーブレットの init() メソッドを呼び出しています。ウォームアップ リクエストにより、実際のリクエストを処理する前に、指定したサーブレットが初期化されます。ただし、ウォームアップ リクエストがない場合、<load-on-startup> に指定したサーブレットは、新しいインスタンスへの最初のリクエストに登録され、それによってリクエストが読み込まれます。前述のように、App Engine は、アプリケーションが新しいインスタンスを必要とするたびにウォームアップ リクエストを発行するとは限りません。

ServletContextListener の使用

サーブレットの呼び出し前に実行する必要があるカスタム ロジックがある場合は、次のようにします。

  1. web.xml ファイルに ServletContextListener を登録します。

    <listener>
      <listener-class>com.company.MyListener</listener-class>
    </listener>
    
  2. クラス、サーブレット、フィルタコードを指定します。

    public class MyListener implements ServletContextListener {
      public void contextInitialized(ServletContextEvent event) {
        // This will be invoked as part of a warmup request, or
        // the first user request if no warmup request was invoked.
      }
      public void contextDestroyed(ServletContextEvent event) {
        // App Engine does not currently invoke this method.
      }
    }
    

ServletContextListener はウォームアップ リクエスト中に実行されます。ウォームアップ リクエストがない場合は、新しいインスタンスへの最初のリクエスト時に実行されます。これにより、読み込みリクエストが発生する場合があります。

カスタム ウォームアップ サーブレットを使用する

カスタム ウォームアップ サーブレットは、ウォームアップ リクエストの処理時にのみ、サーブレットの service メソッドを呼び出します。カスタム ウォームアップ サーブレットに高コストのロジックを含めることで、読み込みリクエストでの読み込み時間の増加を回避できます。

カスタム ウォームアップ サーブレットを作成するには、web.xml_ah_warmup の組み込みサーブレット定義をオーバーライドします。

<servlet>
  <servlet-name>_ah_warmup</servlet-name>
  <servlet-class>com.company.MyWarmupServlet</servlet-class>
</servlet>