Remote API für gebündelte Legacy-Dienste

Das Java SDK enthält eine Bibliothek namens "Remote API", mit der Sie aus jeder beliebigen Java-Anwendung heraus transparent auf App Engine-Dienste zugreifen können. Sie können beispielsweise Remote API verwenden, um auf einen Produktionsdatenspeicher aus einer Anwendung zuzugreifen, die auf Ihrem lokalen Computer ausgeführt wird. Sie können Remote API auch verwenden, um aus einer anderen App Engine-Anwendung auf den Datenspeicher einer App Engine-Anwendung zuzugreifen.

Konfigurieren von Remote API auf dem Server

Die Serverkomponente der Remote API ist ein Java-Servlet, das Teil der App Engine-Laufzeit für Java ist. Dieses Servlet empfängt Requests vom Remote API-Client, sendet sie an den entsprechenden Back-End-Dienst und gibt dann die Ergebnisse des Dienstaufrufs an den Client zurück. Fügen Sie zur Installation des Remote API-Servlets Folgendes zur web.xml-Datei hinzu:

<servlet>
  <display-name>Remote API Servlet</display-name>
  <servlet-name>RemoteApiServlet</servlet-name>
  <servlet-class>com.google.apphosting.utils.remoteapi.RemoteApiServlet</servlet-class>
  <load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
  <servlet-name>RemoteApiServlet</servlet-name>
  <url-pattern>/remote_api</url-pattern>
</servlet-mapping>

Das Servlet gibt einen Fehler zurück, wenn kein authentifizierter Nutzer vorhanden ist oder der authentifizierte Nutzer kein Administrator Ihrer Anwendung ist. Daher ist es nicht nötig, zusätzliche Sicherheitsfunktionen zu konfigurieren. Nachdem Sie Ihre Anwendung mit diesen Einstellungen bereitgestellt haben, kann jede Anwendung, auf der der Remote-API-Client installiert ist, ihre Dienste verwenden. Dazu gehören Python-Clients, die das Python Remote API verwenden.

Remote API auf einem eigenständigen Client konfigurieren

Zur Konfiguration der Client-Komponente von Remote API zur Verwendung innerhalb einer Java-Anwendung fügen Sie ${SDK_ROOT}/lib/impl/appengine-api.jar und ${SDK_ROOT}/lib/appengine-remote-api.jar zu Ihrem Klassenpfad hinzu. Konfigurieren und installieren Sie Remote API anschließend in Ihrem Code:

import com.google.appengine.tools.remoteapi.RemoteApiInstaller;
import com.google.appengine.tools.remoteapi.RemoteApiOptions;

// ...
RemoteApiOptions options = new RemoteApiOptions()
    .server("[APP_ID].[REGION_ID].r.appspot.com", 443)
    .useApplicationDefaultCredential();

RemoteApiInstaller installer = new RemoteApiInstaller();
installer.install(options);
// ... all API calls executed remotely
installer.uninstall();

Der Remote API-Client greift auf Standardanmeldedaten für Anwendungen zurück, die OAuth 2.0 verwenden.

Zum Abrufen von Anmeldedaten führen Sie den folgenden Befehl aus:

gcloud auth application-default login

Genauso einfach können Sie eine Verbindung zu einer App Engine-Anwendung herstellen, die lokal auf dem Entwicklungsserver ausgeführt wird:

RemoteApiOptions options = new RemoteApiOptions()
    .server("localhost", 8888) // server name must equal "localhost"
    .useDevelopmentServerCredential();

Hier ist eine vollständige Java-Anwendung, die bei ihrer Ausführung eine Entität in den Datenspeicher einfügt:

public class RemoteApiExample {

  public static void main(String[] args) throws IOException {
    String serverString = args[0];
    RemoteApiOptions options;
    if (serverString.equals("localhost")) {
      options = new RemoteApiOptions().server(serverString,
        8080).useDevelopmentServerCredential();
    } else {
      options = new RemoteApiOptions().server(serverString,
        443).useApplicationDefaultCredential();
    }
    RemoteApiInstaller installer = new RemoteApiInstaller();
    installer.install(options);
    try {
      DatastoreService ds = DatastoreServiceFactory.getDatastoreService();
      System.out.println("Key of new entity is " + ds.put(new Entity("Hello Remote API!")));
    } finally {
      installer.uninstall();
    }
  }
}

Remote API auf einem App Engine-Client konfigurieren

Sie können Remote API auch verwenden, um über eine andere App Engine-Anwendung auf die Dienste einer App Engine-Anwendung zuzugreifen. Sie müssen ${SDK_ROOT}/lib/appengine-remote-api.jar zum Verzeichnis WEB-INF/lib hinzufügen und dann in Ihrer App Engine-Clientanwendung die Remote API genau wie in Ihrem eigenständigen Java-Client konfigurieren und installieren.

Beachten Sie, dass RemoteApiInstaller das Remote API nur auf dem Thread installiert, der die Installation durchführt. Achten Sie also darauf, keine Instanzen dieser Klasse in Threads freizugeben.

Remote API mit Maven verwenden

Wenn Sie die Remote API-Funktion in Ihrem Maven-Projekt verwenden möchten, fügen Sie der pom.xml-Projektdatei die folgenden Abhängigkeiten hinzu:

<dependency>
  <groupId>com.google.appengine</groupId>
  <artifactId>appengine-remote-api</artifactId>
  <version>1.9.64</version>
</dependency>
<dependency>
  <groupId>com.google.appengine</groupId>
  <artifactId>appengine-api-1.0-sdk</artifactId>
  <version>1.9.64</version>
</dependency>

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.

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

Wenn Sie Abfragen durchlaufen, ruft das SDK jeweils 20 Entitäten aus dem Datenspeicher und ruft immer dann einen neuen Stapel ab, wenn es die vorhandenen verbraucht hat. 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:

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.