Remote API で App Engine にアクセスする

Remote API ライブラリを使用すると、App Engine アプリケーションで使用可能なサービスに Python クライアントからアクセスできます。

例えば、App Engine アプリケーションで Cloud Datastore または Google Cloud Storage を使用する場合、Remote API を使用して Python クライアントからこうしたストレージ リソースにアクセスできます。

また、Remote API を使用すると、ローカルマシンで実行されているアプリやローカルの Remote API インタラクティブ シェルからアプリケーションのデータストアにアクセスできます。Remote API は実際のサービスを利用するので、このアクセスでは、割り当て制限や課金対象のリソースが使用されます。

Python 用の App Engine SDK には Remote API ライブラリが含まれています。

アプリで Remote API アクセスを有効にする

アプリケーションで Remote API を有効にする最も簡単な方法は、アプリの app.yaml ファイルで builtins ディレクティブを使用する方法です。この方法では、デフォルトの URL /_ah/remote_api/ を使用します。同じファイルで url ディレクティブを使用すると、別の URL を指定できます。

builtin

app.yaml ファイルで builtins ディレクティブを指定すると、デフォルトの URL /_ah/remote_api で Remote API を使用できます。

runtime: python27
api_version: 1
threadsafe: true

builtins:
- remote_api: on

URL

app.yamlurl ディレクティブを使用すると、Remote API に別の URL を指定できます。

- url: /some-URL/*
  script: google.appengine.ext.remote_api.handler.application

この変更を行う前に、アプリケーションを App Engine にデプロイしてください。

Remote API シェルを使用する

Python SDK には Remote API シェルが含まれています。このシェルを使用すると、アプリケーションで使用されている App Engine サービスで Python コマンドを実行できます。App Engine にアプリをアップロードしたときに使用された認証情報が自動的に使用されるので、認証情報を入力する必要はありません。

Remote API シェルを開始するには:

  1. ローカルマシンのターミナル ウィンドウで次のコマンドを実行します。

     [SDK-INSTALL-DIRECTORY]/remote_api_shell.py -s [YOUR-PROJECT-ID].appspot.com
    

    [SDK-INSTALL-DIRECTORY] は Python 用 App Engine SDK のパスで置き換え、[YOUR-PROJECT-ID] はプロジェクト ID で置き換えます。

  2. 表示されたインタラクティブ シェルで、必要な Python コマンドを実行します。たとえば、アプリケーションが Cloud Datastore を使用している場合、10 件のレコードを取得するには、次の ndb クエリを実行します。

     >>> from google.appengine.ext import ndb
     >>>
     >>> # Fetch 10 keys from the datastore
     >>> ndb.Query().fetch(10, keys_only=True)
    

ローカル クライアントで Remote API を使用する

ローカル アプリケーションで Remote API を使用すると、App Engine で実行されるアプリが使用しているサービスにもアクセスできます。

ローカル アプリケーションで Remote API を使用するには:

  1. Remote API を有効にします

  2. 次のように、Python ディレクトリ PYTHONPATH 環境変数をエクスポートします。

     export PYTHONPATH=/usr/somedir/v3/bin/python2.7
    

    このパスを Python の実際の場所で置き換えます。

  3. Python 用 App Engine SDK の場所を PYTHONPATH に追加します。

     export GAE_SDK_ROOT="/usr/local/home/mydir/google_appengine"
     export PYTHONPATH=${GAE_SDK_ROOT}:${PYTHONPATH}
    

    上の SDK パスを App Engine SDK の実際のパスで置き換えます。

  4. App Engine SDK のすべてのモジュールが正常にインポートされるように、クライアント コードで dev_appserver をインポートし、dev_appserver.fix_sys_path() を呼び出します。

    try:
        import dev_appserver
        dev_appserver.fix_sys_path()
  5. 次の remote_api_stub コードをアプリケーションに追加します。これにより、コードでプロジェクト ID が渡されます。

    remote_api_stub.ConfigureRemoteApiForOAuth(
        '{}.appspot.com'.format(project_id),
        '/_ah/remote_api')

    Remote API にデフォルトの URL /_ah/remote_api を使用しない場合、使用する URL を反映するように上記のコードを変更する必要があります。remote_api_stub.ConfigureRemoteApiForOAuth の定義とドキュメントについては、SDK ファイル [SDK-INSTALL-DIRECTORY]/google/appengine/ext/remote_api/remote_api_stub.py をご覧ください。

  6. App Engine サービスにアクセスできるように、必要な App Engine インポートと Python コードを追加します。次のサンプルコードでは、プロジェクトのデータストアにアクセスします。

    
    import argparse
    
    try:
        import dev_appserver
        dev_appserver.fix_sys_path()
    except ImportError:
        print('Please make sure the App Engine SDK is in your PYTHONPATH.')
        raise
    
    from google.appengine.ext import ndb
    from google.appengine.ext.remote_api import remote_api_stub
    
    def main(project_id):
        remote_api_stub.ConfigureRemoteApiForOAuth(
            '{}.appspot.com'.format(project_id),
            '/_ah/remote_api')
    
        # List the first 10 keys in the datastore.
        keys = ndb.Query().fetch(10, keys_only=True)
    
        for key in keys:
            print(key)
    
    if __name__ == '__main__':
        parser = argparse.ArgumentParser(
            description=__doc__,
            formatter_class=argparse.RawDescriptionHelpFormatter)
        parser.add_argument('project_id', help='Your Project ID.')
    
        args = parser.parse_args()
    
        main(args.project_id)
  7. アプリケーションを App Engine にデプロイして、Remote API クライアントを開始します。

     python your-client.py YOUR-PROJECT-ID
    

    your-client.py はクライアント モジュールで、YOUR-PROJECT-ID はプロジェクト ID に置き換えます。ここでは、client.py コードサンプルのように、クライアントがコマンドラインからプロジェクト ID を受け取ることを前提としています。

制限事項とベスト プラクティス

remote_api モジュールでは、できる限りネイティブの App Engine データストアと同じ動作をするように最大限の努力が払われています。このため、効率が犠牲になる場合があります。remote_api を使用する際には、以下の点に留意してください。

どのデータストア リクエストにもラウンドトリップがある

HTTP を使ってデータストアにアクセスするため、ローカルなアクセスより若干オーバーヘッドとレイテンシが増えます。高速化と負荷軽減のため、get と put をバッチ処理したり、クエリからエンティティをバッチで取得したりすることによって、ラウンドトリップの回数を減らすようにしてください。これは、remote_api に限らず、データストアの通常の使用方法でも役に立ちます。バッチ オペレーションは単一の Datastore オペレーションと見なされるためです。たとえば、次のコマンドがあるとします。

for key in keys:
  rec = key.get()
  rec.foo = bar
  rec.put()

上記のコマンドの代わりに、次のコマンドを使用できます。

records = ndb.get_multi(keys)
for rec in records:
  rec.foo = bar
  ndb.put_multi(records)

いずれのコマンドも同じ結果になりますが、後者に必要となるラウンドトリップは合計で 2 回だけです。前者の場合、エンティティごとに 2 回のラウンドトリップが必要になります。

remote_api へのリクエストは割り当てを消費する

remote_api では HTTP を使用するため、データストアの API を呼び出すたびに、データストアに対する通常の割り当てに加えて、HTTP リクエストと入出力バイト数の割り当て使用量を消費します。remote_api を使って一括更新を行っている場合には、この点に注意してください。

API での 1 MB の制限が適用される

API のリクエストとレスポンスに対する 1 MB の制限は、ネイティブに実行している場合と同じように適用されます。エンティティが特に大きい場合は、この制限に達しないように、一度に取得または put する数を制限する必要があります。残念ながら、これはラウンドトリップを減らすことと矛盾します。このため、リクエストまたはレスポンスのサイズ制限を超えない範囲で、できるだけ大きなバッチを使用することをおすすめします。ただし、これが問題となる可能性のあるエンティティは多くありません。

クエリの反復処理を避ける

データストアのアクセスで通常使用されるパターンの一例は次のとおりです。

q = MyModel.query()
for entity in q:
  # Do something with entity

このようにアクセスする場合、SDK はデータストアから 20 個単位のバッチでエンティティを取得し、取得したエンティティを使い果たすたびに新しいバッチを取得します。各バッチは remote_api による個別のリクエストで取得する必要がありますが、これでは効率的とは言えません。そのため、remote_api は各バッチに対してまったく新しいクエリを実行し、オフセット機能を使用して結果セットの途中からエンティティを取得します。

必要なエンティティ数がわかる場合は、その個数を指定することにより、1 回のリクエストですべてのエンティティを取得できます。

entities = MyModel.query().fetch(100)
for entity in entities:
  # Do something with entity

必要なエンティティ数がわからない場合は、カーソルを使用して大きな結果セットに対する反復処理を効率的に実行できます。また、これによって通常のデータストア クエリに設定されている 1,000 エンティティの制限を回避することもできます。

トランザクションは効率が悪い

remote_api を使ったトランザクションの実装では、トランザクション中に取得されたエンティティに関する情報と、トランザクション中に put または delete されたエンティティのコピーを蓄積します。トランザクションが commit されると、この情報のすべてが App Engine サーバーに渡されます。そこでは、トランザクションで使用されたすべてのエンティティが再度取得され、変更がないことを確認します。そして、トランザクションが行ったすべての変更を put と delete で実行し、commit します。競合がある場合、サーバーはトランザクションをロールバックしてクライアント側に通知します。クライアント側はこの手順をもう一度最初から繰り返す必要があります。

このアプローチは正しく動作し、機能的にはローカルのデータストアでのトランザクションとまったく同じですが、かなり非効率です。必要なところには必ずトランザクションを使用しつつ、効率の観点から、実行するトランザクションの数と複雑さを減らすようにしてください。

このページは役立ちましたか?評価をお願いいたします。

フィードバックを送信...

Python 2 の App Engine スタンダード環境