使用 Remote API 访问 App Engine

Google Cloud CLI 包含一个 remote_api 软件包,可让您以透明方式从任何 Go 应用访问 App Engine 服务。例如,您可以使用 Remote API 从本地机器上运行的应用或其他 App Engine 应用访问 Datastore。

如需查看 remote_api 软件包的内容,请参阅 remote_api 软件包参考文档。

启用 Remote API

首先,将 remote_api url 处理程序添加到 app.yaml。例如:

- url: /_ah/remote_api
  script: _go_app

这会将网址 /_ah/remote_api 映射到您的 Go 应用。只有应用管理员才能通过 Remote API 处理程序访问此网址。

然后,您可以将以下行添加到任意 .go 源文件,以在项目的其中一个软件包中导入 remote_api 软件包:

import _ "google.golang.org/appengine/remote_api"

在程序初始化期间,remote_api 软件包会为 /_ah/remote_api 路径注册一个处理程序。导入声明中的下划线表示“导入此软件包,但我们不会直接使用它”。如果没有下划线,您将在编译时收到“imported but not used”(已导入,但未使用)错误消息。

最后,将更新部署到 App Engine。例如:

gcloud app deploy app.yaml

在本地客户端中使用 Remote API

远程 API 可用于编写使用 App Engine 服务并访问数据存储区的本地应用。请务必注意,使用远程 API 将占用您正在访问的应用的配额。

开始之前,请确保 App Engine 应用中已启用远程 API。通过使用 remote_api.NewRemoteContext 创建上下文并使用该上下文替换所有 API 调用中的常规 App Engine 上下文,本地应用可以使用 Remote API。

// Copyright 2011 Google Inc. All rights reserved.
// Use of this source code is governed by the Apache 2.0
// license that can be found in the LICENSE file.

package main

import (
	"log"
	"time"

	"golang.org/x/net/context"
	"golang.org/x/oauth2/google"

	"google.golang.org/appengine/datastore"
	"google.golang.org/appengine/remote_api"
)

func main() {
	const host = "<your-app-id>.appspot.com"

	ctx := context.Background()

	hc, err := google.DefaultClient(ctx,
		"https://www.googleapis.com/auth/appengine.apis",
		"https://www.googleapis.com/auth/userinfo.email",
		"https://www.googleapis.com/auth/cloud-platform",
	)
	if err != nil {
		log.Fatal(err)
	}

	remoteCtx, err := remote_api.NewRemoteContext(host, hc)
	if err != nil {
		log.Fatal(err)
	}

	q := datastore.NewQuery("Greeting").
		Filter("Date >=", time.Now().AddDate(0, 0, -7))

	log.Println(q.Count(remoteCtx))
}

要运行此代码,您需要提取这些软件包:

$ go get google.golang.org/appengine/...
$ go get golang.org/x/oauth2/...

您需要提供服务器的主机名和 http.Client 来调用 NewRemoteContext。提供的 http.Client 负责在每次请求中传递所需的身份验证信息。

在上述示例中,golang.org/x/oauth2/google 软件包中的 DefaultClient 通过应用默认凭据提供 OAuth 2 凭据。

限制和最佳做法

remote_api 模块竭尽全力来确保尽可能表现得像本地 App Engine 数据存储区。在某些情况下,这意味着处理效率可能会相对低下。使用 remote_api 时,需牢记以下几点:

每一个数据存储区请求都需要一个往返

因为您通过 HTTP 访问数据存储区,所以开销和延迟会略多于本地访问数据存储区。为了加快速度和降低负载,请尝试通过批处理获取内容和写入内容,并从查询提取批量实体来限制往返次数。这不仅适用于 remote_api,也适用于数据存储区的常规使用,因为批处理操作仅被视为单个数据存储区操作。

对 remote_api 使用配额的请求

由于 remote_api 通过 HTTP 运行,您进行的每个数据存储区调用都会产生对以下配额的使用:HTTP 请求、输入和输出字节,以及常规的数据存储区配额。如果您使用 remote_api 来进行批量更新,请牢记这一点。

1 MB API 限制

在本地运行时,对于 API 请求和响应的 1MB 限制仍然适用。如果您的实体特别大,则可能需要限制一次提取或放置的数量,以免超过此限制。但这与最小化往返次数存在冲突,因此最好的建议是尽可能使用最大的批而不超过请求或响应大小限制。但对于大多数实体来说,这不太可能成为问题。

避免迭代查询

当您进行迭代查询时,SDK 以 20 为一个批次,从数据存储区中提取实体,每当用完现有批次时就提取一个新的批次。由于每一批次都必须在单独请求中由 remote_api 提取,因此这种做法的效率没那么高。反之,remote_api 对每一批次执行一个全新的查询,使用偏移功能来进一步接近结果。

如果您知道所需实体的数目,则可以通过请求所需的数量来在一个请求中完成全部提取。

如果您不知道需要多少实体,则可以使用游标高效地迭代大型结果集。这还可以避开对常规数据存储区查询施加的 1000 实体的限制。

事务效率较低

为通过 remote_api 实施事务,它累积有关在事务内提取的实体的信息,以及在事务内放置或删除的实体的副本。事务被提交时会向 App Engine 服务器发送所有这些信息。在 App Engine 服务器中,事务必须再次提取事务中所使用的所有实体,验证这些实体未被修改,然后放置和删除事务所做的所有更改并将其提交。如果有冲突,服务器将回滚事务并通知客户端,然后客户端必须再次重复这一过程。

此方法可行,并能准确提供由事务在本地数据存储区上提供的功能,但是效率相当低下。在必要时,请务必使用事务,但出于效率的考虑,建议尽量限制所执行事务的数量和复杂性。