2010年3月12日金曜日

GAE/Jのドキュメントを読んでみる その2(The Java Servlet Environment)

以下、ドキュメントを読んだ際のメモ。

The Java Servlet Environment

App Engine は Java Web アプリケーションを Java 6 JVM を用いてサンドボックス内で動作する。App Engine はこの環境内で、リクエストの処理とレスポンスの準備のためにアプリのサーブレットクラスを呼び出す。


Selecting the Java API Version

  • 現段階では、App Engine Java API は1種類しかない。
  • appengine-api-*.jar の * が API と SDK のバージョンを表す。この jar はWEB-INF/lib/ 以下に配置。
  • 互換性は保たれないバージョンがリリースされたらバージョン番号が変わる。その際、jar を差し替えない限り、既存のアプリは古いバージョンを使い続けることができる。

Requests and Domains

  • App Engine は、どのアプリに対するリクエストなのかをドメイン名によって識別する。
  • ドメイン名が application-id.appspot.com のリクエストは、ID が application-id のアプリにルーティングされる。
  • すべてのアプリは、appspot.com のドメイン名を無料で取得できる。
  • appspot.com ドメインは subdomain.application-id.appspot.com というサブドメインをサポートしている。
  • サブドメインは、ドット(.)以外のドメイン名に含むことが許される文字列によって構成される文字列が使用できる。
  • サブドメインを使用した場合でも、そのアプリにルーティングされる。
  • 独自のトップレベルドメインを指定可能。
  • Google Apps では、独自ドメインのサブドメインに Google Mail やその他のサイトをアサインすることができ、App Engine application も同様にできる。便宜上、アプリケーションID登録時に Google Apps domainを設定しておいて、後に Administrator Console から設定することもできる。詳細はこちら
  • これらのURLへのリクエストはすべて Administrator Console でデフォルトとして設定されたバージョンのアプリケーションにルーティングされる。
  • 各バージョンのアプリはそれぞれ独自の URL を持つ。そのため、新バージョンのデプロイとテストを、新バージョンをデフォルトとする前にすることができる。
  • バージョン依存の URL は、appspot.com ドメイン名にアプリのコンンフィグファイルのバージョン識別子を使用する。パターンは version-id.latest.application-id.appspot.com
  • バージョン依存URLにサブドメインを使うことも可能。パターンは subdomain.version-id.latest.application-id.appspot.com
  • リクエストに使用されたドメイン名はアプリケーションに渡されるリクエストデータに含まれる。もしドメイン名によって異なるレスポンスを返したい場合は、リクエストデータをチェックすることで可能。

Requests and Servlets

  • App Engine がアプリへのリクエストを受けると、デプロイメント・ディスクリプタに記述されたサーブレットを呼び出す。その際 Java Servlet API が使用される。
  • App Engine は複数のWebサーバで1つのアプリを動作させ、自動でサーバ数を調整する。そのため、与えられたリクエストはどのサーバにルーティングされるかわからず、前回のリクエストと異なるサーバにルーティングされることもある。

Responses

  • App Engine は servlet を request と response オブジェクトを渡して呼び出し、サーブレットがレスポンスオブジェクトのデータを詰め込んで処理を返すのを待つ。servlet が処理を返したときに、response オブジェクトのデータはユーザに返される。
  • App Engine はクライアントへのデータ送信はサポートせず、より多くのアプリケーション内の処理をこなし、そしてより多くのデータを返す。言い換えれば、App Engine はリクエストを返却するためのデータストリーミングはサポートしない。
  • もしクライアントが gzip 圧縮されたデータを受け付けられる HTTP ヘッダを送ってきた場合、App Engine はレスポンスデータを自動的に圧縮し、適切なヘッダをつける。クライアントが圧縮データを確実に受け付けられるかどうかは、Accept-Encoding と User-Agent の両ヘッダを用いて識別する。独自クライアントは、Accept-Encoding と User-Agent の両ヘッダに gzip を指定することにより、圧縮を強制することが可能。
  • 自分のサイトに管理者アカウントでサインインしている状態でアクセスすると、App Engine はレスポンスヘッダにリクエスト単体の分析をつけてくれる。X-AppEngine-Estimated-CPM-US-Dollars ヘッダは、同様のリクエストが1000件来た場合の金額見積もりを表す。X-AppEngine-Resource-Usage はリクエストで使用されたリソース表し、サーバj巻、CPU時間、APIの使用したCPU時間とミリ秒単位で返す。

The Request Timer

  • リクエストハンドラは時間制限(通常は30秒程度)を持ち、それを超えるとリクエストハンドラは処理を中断する。
  • Java実行環境は、com.google.apphosting.api.DeadlineExceededException を throw して実行を中断する。他の uncaught exceptions と同様、リクエストハンドラがこの例外を受けなかった場合、実行環境は500エラーをクライアントに返す。
  • リクエストハンドラは、レスポンスをカスタマイズするために、このエラーを catch することができる。実行環境は、独自レスポンスを返すために、この例外が起こった後に少しの時間(1秒未満)を与える。
  • リクエストの30秒ルールがあるため、App Engine は短時間で処理可能なリクエスト(数百ミリ秒程度)用に最適化されている。効果的なアプリは大部分のリクエストを即座に返す。そうしないアプリは App Engine のインフラ上ではスケールしない。

The Sandbox

  • App Engine が複数のアプリにリクエストを分散させたり、各アプリ同士が干渉しあわないように、アプリは制限されたサンドボックス環境で実行される。この環境では、アプリはコードの実行、App Engine datastore へのデータ格納とクエリ、App Engine mail の利用、URL fetch、users services、リクエストの確認とレスポンスの準備ができる。
  • App Engine アプリができないことは以下:
  • ファイルシステムへの書き込み。アプリはデータの永続化には App Engine datastore を使用しなくてはならない。ファイルシステムからの読み出しは許可され、アプリケーションと一緒にアップロードされたアプリケーションファイルを読むことはできる。
  • socket のオープンと、他のホストへの直接的なアクセスはできない。アプリは App Engine URL fetch service を使って HTTP もしくは HTTPS リクエストを作成し、80 番ないし 443 番ポートに接続することはできる。
  • サブプロセスやスレッドを生成することができない。アプリへの Web リクエストは単一プロセス内で数秒以内で処理されなくてはならない。レスポンスを返すまでに長時間かかる処理は Web サーバの負荷超過を避けるために中断される。
  • システムコールの呼び出しはできない。

Threads
  • java.lang.ThreadGroup や java.lang.Thread を新規に生成することはできない。これらの制約は thread を使用する JRE のクラスにも適用されている。例えば、アプリは java.util.concurrent.ThreadPoolExecutor や java.util.Timer を新規に作成することはできない。アプリは、Thread.currentThread().dumpStack() 等、現在のスレッドへの操作は可能。
The Filesystem
  • java.io.FileWriter のようなファイルシステムへの書き込みを行うようなクラスは使用できない。java.io.FileReader のようなファイルの読み込みを行うクラスは使用可能。アプリは、Class.getResource() や ServletContext.getResource() のような形で、独自のファイルを resources としてアクセスすることも可能。
  • resource files として扱えるファイルは、ファイルシステム経由でもアクセス可能。デフォルトでは、war ファイル内のすべてのファイルは resource files として扱える。appengine-web.xml ファイルにより、resource files からファイルを除外することも可能。
java.lang.System
  • java.lang.System クラスで App Engine に適用できないものは利用不可能になっている。
  • exit(), gc(), runFinalization(), runFinalizersOnExit() は、何も行わない。
  • inheritedChannel(), console() は null を返す。
  • アプリは JNI コードの用意や直接的な実行はできない。load(), loadLibrary(), setSecurityManager() は java.lang.SecurityException を throw する。
Reflection
  • アプリは自分自身のクラスに対しては無制限でリフレクションを使用可能。
  • JRE と API クラスに対してもリフレクションを使用することは可能だが、public メンバのみに対してのみ可能。
  • アプリは上記以外の自分自身に所属しないクラスに対してリフレクションを使用することはできない。そして、これらの制約を回避するという理由で setAccessible() も使うことができない。
Custom Class Loading
  • カスタムクラスローディングは App Engine でフルサポートされている。しかし、App Engine は、アプリから読み込まれたすべてのクラスに同一のパーミッションを与えるために、すべての ClassLoader をオーバーライドすることに留意する必要がある。もしカスタムクラスローディングを行う場合は、信頼できないサードパーティーのコードに注意する必要がある。

The JRE White List

Logging
  • アプリは java.util.logging.Logger を用いてアプリケーションログにデータを書き出すことができる。
  • アプリのログデータは Administration Console もしくは appcfg.sh request_logs によって参照したり分析したりすることができる。
  • Admin Console は Logger クラスのログレベルを認識し、異なるレベルでの表示が可能。
  • sevlet が標準出力および標準エラー出力に書き出す情報はログに書き出される。
  • 標準出力に出力された情報は INFO レベルでロギングされる。
  • 標準エラー出力に出力された情報は WARNING レベルでロギングされる。
  • log4j のようなほかのロギング用フレームワークは使用可能だが、Admin Console の log level display での詳細な制御をする場合は、ロギング用フレームワークは java.util.logging アダプタを使わなくてはならない。
  • App Engine Java SDK は logging.properties のテンプレートを appengine-java-sdk/config/user/ directory に含んでいる。利用するためには、ファイルを WEB-INF/classes ディレクトリ(もしくは war 以下の任意の場所)にコピーし、システムプロパティ java.util.logging.config.file を WEB-INF/classes/logging.properties (もしくは上記任意の場所にあわせてアプリケーションルートからの相対パスで)に指定する。システムプロパティは appengine-web.xml ファイルに書く。
  • Google Plugin for Eclipse の new project wizard はこれらのロギング設定ファイルを作成し、WEB-INF/classes/ 以下に自動的にコピーする。java.util.logging を使用するためには、このファイルを使用するようにシステムプロパティを設定する必要がある。

The Environment

  • すべてのシステムプロパティと環境変数はアプリに閉じている。
  • システムプロパティと環境変数はデプロイメント・ディクスリプタで設定可能。
  • App Engine は実行環境を特定するために以下の2つのシステムプロパティをセットする。
  • com.google.appengine.runtime.environment は App Engine 上で実行時は Production となり、開発サーバ上の場合は Development となる。
  • com.google.appengine.runtime.version は実行環境のバージョンID。1.3.0等。
  • System.getProperty() を使用する場合、システムプロパティを type-safe API を使ってアクセスすることができる。
  • App Engine は、アプリケーションサーバ上で JVM の初期化時に、以下のシステムプロパティをセットする。
    • file.separator
    • path.separator
    • line.separator
    • java.version
    • java.vendor
    • java.vendor.url
    • java.class.version
    • java.specification.version
    • java.specification.vendor
    • java.specification.name
    • java.vm.vendor
    • java.vm.name
    • java.vm.specification.version
    • java.vm.specification.vendor
    • java.vm.specification.name
    • user.dir

Quotas and Limits

  • 各リクエストは Requests quota にカウントされる。
  • リクエストに含まれるデータは、Incoming Bandwidth (billable) quota にカウントされる。
  • レスポンスに含まれるデータは、Outgoing Bandwidth (billable) quota にカウントされる。
  • HTTP と HTTPS リクエストは Incoming Bandwidth (billable) quota と Outgoing Bandwidth (billable) quota にカウントされる。
  • Admin Console の Quota Details ページでは、Secure Requests、Secure Incoming Bandwidth、Secure Outgoing Bandwidth を別々にレポートし、HTTPS リクエストのみがカウントされる。
  • CPU 処理時間は CPU Time (billable) quota にカウントされる。
  • quotas に関する更なる情報は、Quotas や Admin Console の "Quota Details" セクションを参照のこと。
  • 更に quotas には、リクエストハンドラに以下の制限が適用されている。
Limit Amount
request size 10 megabytes
response size 10 megabytes
request duration 30 seconds
simultaneous dynamic requests 30 *
maximum total number of files (app files and static files) 3,000
maximum size of an application file 10 megabytes
maximum size of a static file 10 megabytes
maximum total size of all application and static files 150 megabytes
* アプリは30リクエストの同時接続が可能。これは、他の追加レイテンシを無視すると、サーバーサイドの平均処理時間を 75ms の場合に (1000 ms/second / 75 ms/request) * 30 = 400 requests/second の処理が可能なことを意味する。CPU負荷の高いアプリの場合は、同一サーバで並行するほかのアプリのために長時間実行されるリクエストの追加レイテンシを被る。静的ファイルへのアクセスは、この制約に該当しない。
  • もしアプリがリソースを効果的に利用し、トラフィックが秒間最大数を超えてしまいそうな場合は、同時アクセス数の制限を上げる要求をすることができる。App Engine は30同時アクセス以上にスケールすることができる。このデフォルトの制限は、パフォーマンスの悪いアプリや、リソースを溜め込む悪意のあるアプリへの対策として存在する。


おいら的重要事項
  • サブドメインが使える。
  • 独自のトップレベルドメインを指定可能。
  • アプリのバージョン毎に異なるURLを持つことができる。
  • ドメイン名はアプリケーションに渡されるリクエストデータに含まれる。
  • ロードバランス時にサーバ・アフィニティは使えない。
  • Accept-Encoding と User-Agent の両ヘッダに gzip が指定されていると、App Engine が自動的によきに計らってくれる。
  • 自分のサイトに管理者アカウントでサインインしている状態でアクセスすると、App Engine はレスポンスヘッダにリクエスト単体の分析をつけてくれる。
  • リクエストの30秒ルール。
  • 30秒を超えた場合の例外は catch することができ、1秒未満だが独自レスポンスを返す時間が与えられる。
  • App Engine のインフラは、リクエストを数百ミリ秒程度で返す場合を想定して最適化されているため、そうしないとスケールしない。
  • ファイルシステムへの書き込みはできない。
  • スレッドの生成はできない。
  • socket を直接使うことはできず、URL fetch service を使って HTTP もしくは HTTPS リクエストを作成し、80 番ないし 443 番ポートに接続することはできる。
  • リフレクションは、自分自身のクラスに対してはフルサポート、JREとAPIのクラスに対しては public メンバに対してのみ可能、その他のクラスに対しては不可能。
  • sevlet が標準出力および標準エラー出力に書き出す情報はログに書き出される。
  • 同時接続数のデフォルトは 30 だが、静的ファイルへのアクセスはこの制約に含まれない。
  • ファイルサイズの上限は静的ファイルもそれ以外も10MBまで。
  • 全ファイルの合計は150MBまで。

疑問点
・1インスタンスで利用可能なメモリサイズはどの程度か?特にヒープサイズは、ホスト内にキャッシュを持つ場合に重要。→ GAE/Jの実験(heapサイズ)参照。100MBまではOKっぽい。

0 件のコメント:

コメントを投稿