Auf App Engine mit Remote API zugreifen

Regions-ID

REGION_ID ist ein abgekürzter Code, den Google anhand der Region zuweist, die Sie beim Erstellen Ihrer Anwendung ausgewählt haben. Der Code bezieht sich nicht auf ein Land oder eine Provinz, auch wenn einige Regions-IDs häufig verwendeten Länder- und Provinzcodes ähneln können. Bei Anwendungen, die nach Februar 2020 erstellt wurden, ist REGION_ID.r in den App Engine-URLs enthalten. Bei Anwendungen, die vor diesem Datum erstellt wurden, ist die Regions-ID in der URL optional.

Hier finden Sie weitere Informationen zu Regions-IDs.

Die Remote API-Bibliothek ermöglicht jedem Python-Client den Zugriff auf Dienste, die für App Engine-Anwendungen verfügbar sind.

Wenn Ihre App Engine-Anwendung beispielsweise Datastore oder Google Cloud Storage verwendet, kann ein Python-Client mithilfe der Remote API auf diese Speicherressourcen zugreifen.

Sie können die Remote API verwenden, um über eine Anwendung, die auf Ihrem lokalen Computer ausgeführt wird, oder über eine lokale interaktive Remote API-Shell auf den Datenspeicher Ihrer Anwendung zuzugreifen. Die Remote API interagiert mit tatsächlichen Diensten, daher verbraucht dieser Zugriff Teile Ihres Kontingents und nutzt kostenpflichtige Ressourcen.

Remote API-Zugriff in einer Anwendung aktivieren

Am einfachsten aktivieren Sie die Remote API über die Anweisung builtins in der Datei app.yaml Ihrer Anwendung. In dieser Datei ist die Standard-URL /_ah/remote_api/ angegeben. Sie können in derselben Datei aber auch die Anweisung url verwenden, um eine andere URL anzugeben.

builtin

Die Anweisung builtins in der Datei app.yaml stellt die Remote API unter der Standard-URL /_ah/remote_api bereit:

runtime: python27
api_version: 1
threadsafe: true

builtins:
- remote_api: on

URL

Mit der Anweisung url in app.yaml können Sie eine andere URL für die Verwendung mit der Remote API angeben:

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

Stellen Sie Ihre Anwendung in App Engine bereit, nachdem Sie diese Änderung vorgenommen haben.

Remote API-Shell verwenden

Das Python SDK enthält eine Remote API-Shell, mit der Sie Python-Befehle in App Engine-Diensten aufrufen können, die von Ihrer Anwendung verwendet werden. Sie müssen keine zusätzliche Authentifizierung bereitstellen, da automatisch dieselben Anmeldedaten verwendet werden, die Sie zum Hochladen der Anwendung in App Engine verwendet haben.

So starten Sie die Remote API-Shell:

  1. Rufen Sie den folgenden Befehl in einem Terminalfenster auf Ihrem lokalen Computer auf:

    SDK-INSTALL-DIRECTORY/remote_api_shell.py -s YOUR-PROJECT-ID. REGION_ID.r.appspot.com

    Ersetzen Sie [SDK-INSTALL-DIRECTORY] durch den Pfad zum App Engine SDK für Python und [YOUR-PROJECT-ID] durch Ihre Projekt-ID.

  2. Rufen Sie in der angezeigten interaktiven Shell die Python-Befehle auf, die Sie ausführen möchten. Wenn Ihre Anwendung beispielsweise Datastore verwendet, können Sie die folgende ndb-Abfrage aufrufen, um 10 Datensätze abzurufen:

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

Remote API in einem lokalen Client verwenden

Sie können die Remote API auch in lokalen Anwendungen verwenden, um auf Dienste zuzugreifen, die von Ihrer Anwendung in App Engine verwendet werden.

So verwenden Sie die Remote API in einer lokalen Anwendung:

  1. Aktivieren Sie die Remote API.

  2. Exportieren Sie die Umgebungsvariable PYTHONPATH für Ihr Python-Verzeichnis. Beispiel:

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

    Ersetzen Sie diesen Pfad durch die tatsächlichen Werte für Ihren Python-Speicherort.

  3. Fügen Sie das App Engine SDK für den Python-Speicherort zu PYTHONPATH hinzu:

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

    Ersetzen Sie den oben angezeigten SDK-Pfad durch den tatsächlichen Pfad zum App Engine SDK.

  4. Importieren Sie dev_appserver in Ihren Clientcode und rufen Sie dev_appserver.fix_sys_path() auf, um dafür zu sorgen, dass alle SDK-Module für App Engine ordnungsgemäß importiert werden:

    try:
        import dev_appserver
        dev_appserver.fix_sys_path()
  5. Fügen Sie Ihrer Anwendung den folgenden remote_api_stub-Code hinzu. Achten Sie dabei darauf, dass Sie Ihre Projekt-ID in Ihrem Code übergeben:

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

    Wenn Sie für die Remote API nicht die Standard-URL /_ah/remote_api verwenden, müssen Sie den obigen Code so ändern, dass er der von Ihnen verwendeten URL entspricht. Die Definition und Dokumentation zu remote_api_stub.ConfigureRemoteApiForOAuth finden Sie in der SDK-Datei [SDK-INSTALL-DIRECTORY]/google/appengine/ext/remote_api/remote_api_stub.py.

  6. Fügen Sie alle erforderlichen App Engine-Importe und den Python-Code hinzu, um auf die gewünschten App Engine-Dienste zuzugreifen. Der folgende Beispielcode greift auf den Datenspeicher des Projekts zu:

    
    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. Wenn Ihre Anwendung in App Engine bereitgestellt wurde, starten Sie Ihren Remote API-Client:

     python your-client.py YOUR-PROJECT-ID
    

    Ersetzen Sie your-client.py durch Ihr Client-Modul und YOUR-PROJECT-ID durch Ihre Projekt-ID. Dies setzt voraus, dass Ihr Client entsprechend dem Beispielcode client.py die Projekt-ID als Eingabe für die Befehlszeile akzeptiert.

Beschränkungen und Best Practices

Bei dem Modul „remote_api“ wurde großer Wert darauf gelegt, dass es sich nach Möglichkeit genau so wie der native App Engine-Datenspeicher verhält. In einigen Fällen führt dies allerdings zu einer geringeren Effizienz. Bei der Verwendung von remote_api müssen einige Punkte berücksichtigt werden:

Umlauf bei jeder Datenspeicher-Anforderung

Da Sie über HTTP auf den Datenspeicher zugreifen, sind der Aufwand und die Latenz etwas höher als beim lokalen Zugriff. Zur Erhöhung der Geschwindigkeit und zur Verringerung der Last sollten Sie versuchen, die Anzahl der durchgeführten Umläufe zu begrenzen, indem Sie „get“- und „put“-Anforderungen als Stapelvorgänge ausführen und Entitäten stapelweise aus den Abfragen abrufen. Dies hilft nicht nur bei der Verwendung von remote_api, sondern auch bei der Verwendung des Datenspeichers im Allgemeinen, da ein Batchvorgang nur als einzelner Datenspeichervorgang betrachtet wird. Beispielsweise können Sie anstatt

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

Folgendes verwenden:

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

Beide Beispiele haben dieselbe Wirkung, bei letzterem sind jedoch nur insgesamt zwei Round-Trips erforderlich, während beim ersteren zwei Round-Trips für jede Entität benötigt werden.

Quotenverbrauch für "remote_api"-Anfragen

Da remote_api über HTTP ausgeführt wird, führt jeder ausgeführte Datenspeicheraufruf neben der Verwendung des erwarteten Datenspeicher-Kontingents zu einer Kontingentverwendung eingehender und ausgehender Byte für HTTP-Anforderungen. Beachten Sie dies, wenn Sie remote_api für Bulk-Updates verwenden.

1-MB-Obergrenze für API

Wie bei der nativen Ausführung gilt auch hier die 1-MB-Obergrenze für API-Anforderungen und -Antworten. Bei besonders großen Entitäten müssen Sie möglicherweise die jeweils abgerufenen oder abgelegten Daten begrenzen, um unter dieser Obergrenze zu bleiben. Diese Vorgabe steht leider im Widerspruch zu der Reduzierung der Umläufe. Daher sollten die Batches jeweils so groß gewählt werden, wie es möglich ist, ohne die Größenbeschränkungen für Anforderung oder Antwort zu überschreiten. Bei den meisten Entitäten ist dies jedoch vermutlich kein Problem.

Iteration über Abfragen vermeiden

Ein häufiges Muster beim Datenspeicherzugriff sieht so aus:

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

Dabei ruft das SDK Entitäten aus dem Datenspeicher in Stapeln zu je 20 ab. Es wird jeweils ein neuer Stapel abgerufen, wenn die bestehenden verbraucht wurden. Da jeder Stapel von remote_api in einer separaten Anforderung abgerufen werden muss, kann hierbei nicht dieselbe Effizienz erreicht werden. Stattdessen führt remote_api für jeden Stapel eine völlig neue Abfrage aus und verwendet dabei die Offset-Funktion, um zu weiteren Ergebnissen vorzudringen.

Wenn Sie wissen, wie viele Entitäten Sie benötigen, können Sie den gesamten Abruf in einer einzigen Anforderung durchführen, indem Sie die benötigte Anzahl anfordern:

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

Wenn Sie nicht wissen, wie viele Entitäten Sie benötigen, können Sie Cursors verwenden, um große Ergebnismengen effizient zu iterieren. Dadurch können Sie gleichzeitig die Obergrenze von 1.000 Entitäten umgehen, die für normale Datenspeicherabfragen gilt.

Geringere Effizienz bei Transaktionen

Zum Implementieren von Transaktionen über remote_api werden Informationen zu den in der Transaktion abgerufenen Entitäten sowie Kopien der Entitäten, die in der Transaktion abgelegt oder gelöscht wurden, angesammelt. Wenn die Transaktion in einem Commit-Vorgang übergeben wird, werden alle diese Informationen an den App Engine-Server gesendet. Dort müssen erneut alle Entitäten, die in der Transaktion verwendet wurden, abgerufen werden, es muss überprüft werden, dass sie nicht geändert wurden, und dann müssen alle Änderungen, die in der Transaktion vorgenommen wurden, abgelegt und gelöscht werden und schließlich muss ein Commit-Vorgang durchgeführt werden. Bei einem Konflikt macht der Server die Transaktion rückgängig und benachrichtigt die Client-Seite, die dann den Vorgang noch einmal von vorne beginnen muss.

Diese Vorgehensweise funktioniert und dupliziert die von den Transaktionen bereitgestellten Funktionen exakt im lokalen Datenspeicher, ist jedoch ziemlich ineffizient. Wenn nötig, sollten Sie unbedingt Transaktionen verwenden. Versuchen Sie jedoch zugunsten der Effizienz die Anzahl und Komplexität der ausgeführten Transaktionen möglichst gering zu halten.