通过 App Engine,您可以构建使用 Google 的可扩展基础架构和服务的网页应用。 App Engine 使用 Java 8 JVM 运行 Web 应用。在此环境中,App Engine 会调用应用的 servlet 类来处理请求并准备响应。
App Engine 平台中内置了许多 API 服务,可供您的代码进行调用。您的应用还可以配置以指定时间间隔运行的计划任务。
为您的应用指定 Java 8 运行时
如需让您的应用使用 Java 8 运行时,请在 appengine-web.xml
文件中添加以下行:
<runtime>java8</runtime>
platform/google_appengine/google/appengine/tools/java/lib/impl/appengine-api.jar
下 Google Cloud CLI 随附的 appengine-api.jar
文件表示适用于 Java 的 App Engine API。您还可以使用 Maven 代码库访问此文件来列出所有版本。
您可以通过在应用的 WEB-INF/lib/
目录中添加此 JAR 来选择应用使用的 API 版本,或使用 Maven 来处理依赖项。如果发布了新版本的 Java 运行时环境,而该版本引入了与现有应用不兼容的更改,则该环境将具有新的主要版本号。
使用 Maven 处理依赖项
您可以使用 Maven 来管理所有依赖项。 例如,此pom.xml
条目包含 Maven Central 提供的最新 App Engine API (Rappengine-api-1.0-sdk
):
<dependency> <groupId>com.google.appengine</groupId> <artifactId>appengine-api-1.0-sdk</artifactId> <version></version> </dependency>
沙盒
App Engine Java 运行时跨多个网络服务器分发应用请求,可防止应用之间相互干扰。 App Engine 应用的响应速度不能太慢。 向应用发出的网络请求必须在请求超时限制内进行处理。在此时限内未做出响应的进程会被终止,以避免网络服务器过载。请注意,用户只能将文件写入到 /tmp
目录。
/tmp
中的文件将占用分配给您的实例的内存。存储在此位置的文件仅供该实例使用,且仅可在该特定实例的生命周期内使用。
应用获取资源文件的常用方法是,使用应用将您所依赖的文件打包到 WEB-INF
下,然后使用 Class.getResource()
、ServletContext.getResource()
或类似方法从应用中加载这些文件。默认情况下,WAR 中的所有文件都是“资源文件”。 您可以使用 appengine-web.xml
文件将文件从此集中排除。
类加载器 JAR 排序
有时,为了解决类名称之间的冲突,可能需要重新定义扫描 JAR 文件以查找类的顺序。在这些情况下,可以通过在 appengine-web.xml
文件中添加包含 <priority-specifier>
元素的 <class-loader-config>
元素,将加载优先级授予特定 JAR 文件。例如:
<class-loader-config>
<priority-specifier filename="mailapi.jar"/>
</class-loader-config>
这会将“mailapi.jar
”作为第一个进行类搜索的 JAR 文件,而禁止目录 war/WEB-INF/classes/
中的那些文件。
如果多个 JAR 文件已按优先顺序排序,则将使用其原始加载顺序(相对于彼此)。换句话说,<priority-specifier>
元素本身的顺序无关紧要。
线程
在 Java 8 运行时中,您可以使用 App Engine 的 ThreadManager API 和 Java 的内置 API(例如 new Thread()
)创建线程。目前,如果要调用 App Engine API (com.google.appengine.api.*
),您必须从请求线程或使用 ThreadManager API 创建的线程中调用这些 API。
应用可以执行以下操作:
- 实施
java.lang.Runnable
。 - 通过调用
com.google.appengine.api.ThreadManager.currentRequestThreadFactory()
来创建线程工厂。 - 调用工厂的
newRequestThread
方法,传入Runnable
、newRequestThread(runnable)
,或将com.google.appengine.api.ThreadManager.currentRequestThreadFactory()
返回的工厂对象与ExecutorService
一起使用(例如Executors.newCachedThreadPool(factory)
)。
如果您通过 currentRequestThreadFactory()
创建 ThreadPoolExecutor
,则必须在 Servlet 请求完成之前明确调用 shutdown()
。否则,请求将无法完成,并且应用服务器最终会失败。
请注意,某些库可能会为您创建 ThreadPoolExecutor。
应用程序可以对当前线程执行操作,例如 thread.interrupt()
。
每个请求仅限于 50 个并发 App Engine API 请求线程。
使用线程时,请使用高级并发对象,例如 Executor
和 Runnable
。这些对象可处理许多细微但非常重要的并发细节,如中断、调度和簿记。
工具
支持的 IDE
通过 Cloud Tools for IntelliJ,您可以在 IntelliJ IDEA 内运行和调试 App Engine 应用。您可以在 IDE 内将 App Engine 项目实时部署到生产环境中。
支持的构建工具
为加快开发过程,您可以使用适用于 Apache Maven 或 Gradle 的 App Engine 插件:
本地开发服务器
开发服务器在本地计算机上运行您的应用以进行开发和测试。服务器模拟 Datastore 服务。开发服务器还可以根据应用在测试期间执行的查询生成 Datastore 索引的配置。
并发和延迟
应用的延迟对处理流量所需的实例数量影响最大。如果您快速处理请求,则单个实例可以处理大量请求。
单线程实例可以处理一个并发请求。 因此,延迟时间与每秒可在实例上处理的请求数之间存在着直接关系。例如,10 毫秒的延迟时间等同于每个实例每秒处理 100 个请求。多线程实例可以处理多个并发请求。因此,所用 CPU 与每秒请求数之间存在直接关系。
Java 应用支持并发请求,因此单个实例可以在等待其他请求完成时处理新的请求。并发处理能力可显著减少应用所需的实例数量,但您需要设计应用以实现多线程。
例如,如果 B4 实例(大约 2.4GHz)为每个请求消耗 10 个兆周期,则每个实例每秒可以处理 240 个请求。如果它为每个请求消耗 100 个兆周期,则每个实例每秒可以处理 24 个请求。这些数字是理想的情况,但就您可以在实例上完成的任务而言,它们相当贴近实际情况。
App Engine Java 版本
以版本 2.x.x
开头的所有已发布工件都使用开源发布机制。以版本 1.9.9xx
或更早版本开头的已发布工件使用内部构建系统。如需了解详情,请参阅 GitHub 代码库。
环境变量
以下环境变量由运行时设置:
环境变量 | 说明 |
---|---|
GAE_APPLICATION
|
App Engine 应用的 ID。此 ID 以“region code~”为前缀,例如“e~”(对于在欧洲部署的应用)。 |
GAE_DEPLOYMENT_ID |
当前部署的 ID。 |
GAE_ENV |
App Engine 环境。设置为 standard 。 |
GAE_INSTANCE |
当前运行您的服务的实例的 ID。 |
GAE_RUNTIME |
在 app.yaml 文件中指定的运行时环境。 |
GAE_SERVICE |
在 app.yaml 文件中指定的服务名称。如果未指定服务名称,则将其设置为 default 。 |
GAE_VERSION |
服务的当前版本标签。 |
GOOGLE_CLOUD_PROJECT |
与您的应用关联的 Google Cloud 项目 ID。 |
PORT |
接收 HTTP 请求的端口。 |
您可以在 app.yaml
文件中定义其他环境变量,但不能替换上述值。