기존 번들 서비스용 Remote API

자바 SDK에는 모든 자바 애플리케이션에서 App Engine 서비스에 투명하게 액세스할 수 있는 Remote API라는 라이브러리가 포함되어 있습니다. 예를 들어 Remote API를 사용하여 로컬 머신에서 실행 중인 앱에서 프로덕션 Datastore에 액세스할 수 있습니다. 또한 Remote API를 사용하여 App Engine 앱에서 다른 App Engine 앱의 Datastore에 액세스할 수도 있습니다.

서버에서 Remote API 구성

Remote API의 서버 구성요소는 자바용 App Engine 런타임의 일부인 자바 서블릿입니다. 이 서블릿은 Remote API 클라이언트로부터 요청을 수신하여 적절한 백엔드 서비스에 전달하고 서비스 호출 결과를 클라이언트에게 반환합니다. Remote API 서블릿을 설치하려면 다음을 web.xml에 추가합니다.

<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>

인증된 사용자가 없거나 인증된 사용자가 애플리케이션의 관리자가 아닌 경우 서블릿은 오류를 반환하므로 보안을 추가로 구성할 필요가 없습니다. 이 설정으로 앱을 배포하고 나면 Remote API 클라이언트가 설치된 모든 앱에서 해당 서비스를 사용할 수 있습니다. 여기에는 Python Remote API를 사용하는 Python 클라이언트도 포함됩니다.

독립형 클라이언트에서 Remote API 구성

자바 애플리케이션 내에서 사용할 수 있도록 Remote API의 클라이언트 구성요소를 구성하려면 클래스 경로에 ${SDK_ROOT}/lib/impl/appengine-api.jar${SDK_ROOT}/lib/appengine-remote-api.jar를 추가합니다. 그런 후 코드에서 다음과 같이 Remote API를 구성하고 설치합니다.

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();

Remote API 클라이언트는 OAuth 2.0을 사용하는 애플리케이션 기본 사용자 인증 정보를 사용합니다.

사용자 인증 정보를 가져오려면 다음을 실행합니다.

gcloud auth application-default login

개발 서버에서 로컬로 실행되는 App Engine 앱에도 다음과 같이 손쉽게 연결할 수 있습니다.

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

다음은 실행될 때 Datastore에 항목을 삽입하는 완성된 자바 애플리케이션입니다.

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();
    }
  }
}

App Engine 클라이언트에서 Remote API 구성

Remote API를 사용하여 App Engine 앱에서 다른 App Engine 앱의 서비스에 액세스할 수도 있습니다. 독립형 자바 클라이언트에서와 마찬가지로 WEB-INF/lib 디렉터리에 ${SDK_ROOT}/lib/appengine-remote-api.jar를 추가하고 클라이언트 App Engine 앱에서 Remote API를 구성 및 설치해야 합니다.

RemoteApiInstaller는 설치를 수행하는 스레드에만 Remote API를 설치하므로 스레드 간에 이 클래스의 인스턴스를 공유하지 않도록 주의합니다.

Maven에 Remote API 사용하기

Maven 프로젝트에서 Remote API 기능을 사용하려면 다음 종속 항목을 프로젝트 pom.xml 파일에 추가합니다.

<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>

제한사항 및 권장사항

remote_api 모듈은 기본 App Engine Datastore와 완전히 동일하게 작동되도록 하기 위해 최대한으로 시도합니다. 즉, 경우에 따라 효율성이 떨어지는 작업을 수행하기도 한다는 의미입니다. 따라서 remote_api를 사용할 때는 다음 사항에 주의하시기 바랍니다.

모든 Datastore 요청에 왕복이 필요함

HTTP를 통해 Datastore에 액세스하는 경우 로컬에서 액세스할 때보다 오버헤드와 지연 시간이 좀 더 늘어날 수 있습니다. 시간을 단축하고 부하를 줄이기 위해서는 get과 put 작업을 일괄 처리하고 쿼리 항목을 일괄적으로 가져와 왕복 횟수를 제한해야 합니다. 일괄 작업은 단일 Datastore 작업으로만 간주되기 때문에 이 방식은 remote_api뿐만 아니라 일반적으로 Datastore를 사용할 때도 유용합니다.

remote_api 요청 시 할당량이 사용됨

remote_api가 HTTP를 통해 작동하므로 Datastore를 호출할 때마다 HTTP 요청에 대한 할당량(바이트 단위 입출력)뿐만 아니라 일반적으로 예상되는 Datastore 할당량이 차감됩니다. 일괄 업데이트에 remote_api를 사용하는 경우 이 점을 염두에 두시기 바랍니다.

1MB API 제한 적용

기본 실행에서와 마찬가지로 API 요청 및 응답에는 1MB 제한이 계속 적용됩니다. 특히 항목 크기가 큰 경우 이 한도가 초과되지 않도록 한 번에 수행하는 fetch 또는 put 작업 횟수를 제한해야 할 수 있습니다. 이 경우 왕복을 최소화하는 접근 방식과 상충되기 때문에 요청 또는 응답 크기의 제한을 넘지 않는 범위 내에서 가장 큰 배치를 사용하는 것이 좋습니다. 그러나 대부분의 항목에서는 이 제한이 문제가 되지 않습니다.

쿼리 반복 방지

쿼리를 반복 실행하는 경우 SDK에서는 Datastore의 항목을 20개 단위의 배치로 가져오며 기존의 항목이 소모될 때마다 새 배치를 가져옵니다. 각 배치는 remote_api를 통해 별도 요청으로 가져와야 하기 때문에 효율성이 떨어질 수밖에 없습니다. 대신 remote_api는 오프셋 기능을 사용하여 배치별로 완전히 새로운 쿼리를 실행하므로 결과의 정확성이 높아집니다.

필요한 항목 수를 알고 있다면 필요한 숫자를 요청하는 방식으로 하나의 요청에서 전체 가져오기를 처리할 수 있습니다.

원하는 항목 수를 모르는 경우에는 커서를 사용하여 큰 결과 집합을 효율적으로 반복할 수 있습니다. 이렇게 하면 일반적인 Datastore 쿼리에 적용되는 1,000개 항목 제한을 피할 수 있습니다.

트랜잭션의 효율성이 떨어짐

remote_api를 통해 트랜잭션을 구현하기 위해 트랜잭션 내에서 가져온 항목에 대한 정보와 트랜잭션 내에서 배치 또는 삭제한 항목의 사본이 축적됩니다. 트랜잭션이 커밋되면 이 모든 정보가 App Engine 서버로 전송되며, 이때 트랜잭션에 사용된 모든 항목을 다시 가져와 변경되지 않았는지 확인한 다음 트랜잭션에 적용된 모든 변경사항에 대해 put 및 delete 작업을 수행한 후 커밋합니다. 충돌이 발생하면 서버가 트랜잭션을 롤백하고 클라이언트 측에 이를 알립니다. 그러면 클라이언트가 전체 프로세스를 처음부터 다시 반복해야 합니다.

이 접근 방식은 제대로 작동하며 트랜잭션에서 제공된 기능을 로컬 Datastore에 정확하게 복제하지만, 다소 비효율적입니다. 따라서 어떤 경우에도 꼭 필요한 경우에만 트랜잭션을 사용해야 하며 효율성을 위해 실행할 트랜잭션의 수와 복잡성을 제한해야 합니다.