Python 2 ランタイム環境

App Engine では、Python プログラミング言語を使用してウェブ アプリケーションを作成できます。また、プロのデベロッパーが世界レベルのウェブ アプリケーションの作成に使用する数多くの Python 用ライブラリ、ツール、フレームワークを利用できます。作成した Python アプリケーションは、Google のスケーラブルなインフラストラクチャ上で動作し、大規模な永続的ストレージとサービスを利用します。

はじめに

App Engine では、あらかじめ用意されている Python インタープリタを使用して、Python アプリケーション コードを安全な「サンドボックス」環境で実行します。アプリは、この環境と通信することで、ウェブ リクエストの受信、作業の実行、レスポンスの送信を行います。

Python ウェブ アプリケーションは、WSGI プロトコルを使用して App Engine ウェブサーバーと情報を交換します。そのため、アプリケーションは、WSGI 互換のさまざまなウェブ アプリケーション フレームワークを利用できます。App Engine には、webapp2 というシンプルなウェブ アプリケーション フレームワークが含まれているため、簡単に開発を開始できます。大規模なアプリケーションの場合には、Django など、実績のあるサードパーティ製フレームワークを App Engine と連携させることができます。

インタープリタは、作成したアプリケーションに含めた Python モジュールや、Python 標準ライブラリなど、あらゆる Python コードを実行できます。ただし、インタープリタはピュアな Python 環境であるため、C コードで作成された Python モジュールを読み込むことはできません。

安全なサンドボックス環境は、サービスとセキュリティ上の理由から、作成したアプリケーションを隔離します。サンドボックス環境では、アプリは、他のアプリのパフォーマンスとスケーラビリティに影響しない処理しか実行できないようになります。たとえば、ローカル ファイル システムにデータを書き込むことはできません。また、任意のネットワークに接続することもできません。代わりに、App Engine が提供するスケーラブルなサービスを利用して、データの保存やインターネット経由の通信を行います。サンドボックス制限内では動作しない Python モジュールを標準ライブラリからインポートしようとすると、Python インタープリタは例外を生成します。

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

Python 2 ランタイムを選択する

app.yaml 構成ファイルで Python ランタイム環境を指定します。アプリケーションを App Engine にデプロイするときに、このファイルが使用されます。たとえば、Python バージョン 2.7 を使用するには、次の行を app.yaml ファイルに追加します。

runtime: python27
api_version: 1
threadsafe: true
...

1 つ目の要素 runtime で、Python ランタイム環境を選択します。

2 番目の要素 api_version で、使用する Python ランタイム環境のバージョンを選択します。現時点で、App Engine Python 環境のバージョンは 1 の 1 つだけです。App Engine チームで環境に行う変更が既存のコードと互換性がない場合、新しいバージョン ID でリリースします。api_version 設定を変更してアプリをアップロードするまで、アプリは選択したバージョンを使用できます。

app.yaml ファイルの詳細と App Engine にアプリをデプロイする方法については、app.yaml リファレンスPython 2.7 への移行Python アプリのデプロイをご覧ください。

サンドボックス

App Engine が複数のアプリケーションへのリクエストを複数のウェブサーバーに分散できるようにして、アプリケーションが相互に干渉しないようにするために、アプリケーションは制限された「サンドボックス」環境で実行されます。この環境でアプリケーションは、コードの実行、Datastore 内でのデータの保存とクエリ、App Engine メール、URL 取得、ユーザー サービスの使用、ユーザーのウェブ リクエストの確認とレスポンスの準備が可能となります。

App Engine アプリケーションでは、次のことはできません。

  • ファイルシステムへの書き込み。アプリケーションは、データを永続的に保存するために、Datastore を使用する必要があります。ファイルシステムからの読み取りは可能です。また、アプリケーションでアップロードされたアプリケーション ファイルはすべて利用可能です。

  • 遅いレスポンス。アプリケーションへのウェブ リクエストは、数秒以内に処理される必要があります。レスポンスまでに非常時に長い時間がかかるプロセスは、ウェブサーバーの過負荷を防ぐために終了します。

  • その他の種類のシステムコールの実行。

Python でサンドボックス化する

Python 2.7 ランタイムを使用している場合、.pyc ファイルをアップロードして使用できますが、同じファイルの .py.pyc をアップロードすることはできません。.py または .pyc ファイル(あるいはその組み合わせ)を含む zip ファイルをアップロードできます。.pyc ファイルをアップロードする場合には、次の点に注意してください。

  • CGI スクリプトの場合、.pyc ファイルをアップロードした場合も、スクリプト ハンドラではファイルの拡張子に引き続き .py を使用する必要があります。
  • デフォルトでは、デプロイ時に .pyc ファイルがスキップされます。.pyc ファイルがスキップされないようにするには、app.yaml ファイル内の skip_files 要素をオーバーライドする必要があります。
  • .pyc ファイルを作成するには、Python 2.7 を使用する必要があります。開発用のマシンで Python の異なるバージョン(Python 2.6 など)を使用する場合には、バージョン 2.7 を取得して互換性のある .pyc ファイルを作成する必要があります。

ピュア Python 2

Python ランタイム環境のコードはすべてピュア Python である必要があり、C 拡張やコンパイルが必要な他のコードを含めることはできません。

この環境には Python 標準ライブラリが含まれています。ただし、一部のモジュールは、コア関数が App Engine でサポートされないため、無効になっています(ネットワーク接続やファイル システムへの書き込みなど)。また、os モジュールは使用できますが、サポートされていない機能は無効になっています。サポートされていないモジュールをインポートしようとした場合や、サポートされていない機能を使用しようとした場合は、例外が発生します。

標準ライブラリの一部のモジュールは、App Engine で動作するように置換、カスタマイズされています。対象となるモジュールは、2 つの Python ランタイムで異なります(下記参照)。

Python バージョン 2.7 のカスタム ライブラリ

Python バージョン 2.7 ランタイムでは、次のモジュールが置換またはカスタマイズされています。

  • tempfile は無効になっています。ただし、TemporaryFile には StringIO のエイリアスが設定されます。

  • logging は使用可能です。使用することを強くおすすめします。ロギングをご覧ください。

Python 標準ライブラリと App Engine ライブラリ以外に、Python バージョン 2.7 ランタイムにはサードパーティ ライブラリも含まれています。

サードパーティ ライブラリを追加する

アプリケーションに Python のサードパーティ ライブラリを追加するには、アプリケーション ディレクトリにコードを配置します。アプリケーション ディレクトリのライブラリのディレクトリにシンボリック リンクを作成すると、そのリンクが参照されて、App Engine にデプロイするアプリにライブラリが含まれるようになります。

Python モジュールのインクルード パスには、アプリケーションのルート ディレクトリ(app.yaml ファイルを含むディレクトリ)が含まれます。アプリケーションのルート ディレクトリに作成した Python モジュールは、ルートからのパスでアクセスできます。Python がこれらのサブディレクトリをパッケージとして認識できるように、必要な __init__.py ファイルをサブディレクトリに作成することを忘れないでください。また、ライブラリで C 拡張が不要になるようにしてください。

スレッド

Python バージョン 2.7 では、thread または threading モジュールを使用してスレッドを作成できます。リクエストが終了すると、ランタイムがスレッドを結合します。リクエストの終了後にスレッドを実行することはできません。

バックグラウンド スレッド

手動または基本のスケーリングのインスタンスで実行するコードは、バックグラウンド スレッドを開始できます。このスレッドは、スレッドを生成したリクエストよりも長く存続できます。これにより、インスタンスは任意の周期またはスケジュールによってタスクを実行できるようなるほか、リクエストがユーザーに返された後でもバックグラウンドで作業を続行できるようになります。

バックグラウンド スレッドの os.environ とロギング エンティティは、スレッドを生成するエンティティとは無関係です。

App Engine 用 SDK から google.appengine.api.background_thread モジュールをインポートする必要があります。

from google.appengine.api import background_thread

BackgroundThread クラスは通常の Python threading.Threadclass クラスに似ていますが、スレッドを生成したリクエストよりも「長く存続」できます。start_new_background_thread() 関数はバックグラウンド スレッドを作成して開始します。

# sample function to run in a background thread
def change_val(arg):
    global val
    val = arg

if auto:
    # Start the new thread in one command
    background_thread.start_new_background_thread(change_val, ['Cat'])
else:
    # create a new thread and start it
    t = background_thread.BackgroundThread(
        target=change_val, args=['Cat'])
    t.start()
App Engine API で作成される同時実行バックグランド スレッドの最大数はインスタンスごとに 10 個です(この上限は App Engine API とは関係のない、通常の Java スレッドには適用されません)。

ツール

App Engine 用 SDK には、アプリケーションのテスト、アプリケーション ファイルのアップロード、Datastore インデックスの管理、ログデータのダウンロード、Datastore に対する大量データのアップロードを行うためのツールが用意されています。

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

gcloud ツールにより、App Engine で動作しているアプリケーションに対するすべてのコマンドライン操作が処理されます。gcloud app deploy を使用すると、アプリケーションを App Engine にアップロードできます。また、Datastore インデックス構成などの個別の構成ファイルを更新することもできます。これにより、コードをデプロイする前に新しいインデックスを作成できます。また、アプリのログデータを表示して、独自のツールでアプリのパフォーマンスを分析することもできます。

同時実行とレイテンシ

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

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

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

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

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

環境変数

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

環境変数 説明
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 ファイル内で追加の環境変数を定義できますが、上記の値をオーバーライドすることはできません。