实例的管理方式

实例是 App Engine 的基本组件,提供托管应用所需的所有资源。在任意时间点,您的应用都可能在一个或多个实例上运行,而请求将分散到正在运行的所有实例。每个实例都有一个安全层,确保不会发生意外的相互影响。

App Engine 可以在流量波动时自动创建和关停实例,您也可以指定运行的实例数,而不考虑流量。如需确定创建新实例的方式和时间,请为您的应用指定扩缩类型。扩缩设置在 app.yaml 文件的 App Engine 版本级层应用。

扩缩类型

App Engine 支持以下扩缩类型,这些类型用于控制创建实例的方式和时间:

  • 自动(默认)
  • 基本
  • 手动

您可以在应用的 app.yaml 中指定扩缩类型。 默认情况下,您的应用使用自动扩缩功能,这意味着 App Engine 将管理空闲实例的数量。

自动扩缩
自动扩缩会根据请求速率、响应延迟时间和其他应用指标来创建实例。您可以配置 automatic_scaling 元素为其中的每个指标指定阈值,以及指定应始终保持运行的最小实例数。
基本扩缩
基本扩缩会在应用收到请求时创建实例。当应用变为空闲状态时,每个实例都将关停。基本扩缩非常适合间歇性工作或由用户活动驱动的工作。
手动扩缩
手动扩缩会指定无论负载水平如何都持续运行的实例数。这种类型支持复杂初始化等任务,以及持久依赖内存状态的应用。
下表比较了三种扩缩类型的性能特征:

功能 自动扩缩 基本扩缩 手动扩缩
请求超时 HTTP 请求和任务队列任务为 10 分钟。如果您的应用未在此时间限制内返回请求,则 App Engine 会中断请求处理程序并发出错误以供代码处理。

对于旧版运行时(Java 8、PHP 5 和 Python 2):

  • Cron 作业的任务队列任务和请求的超时时间为 10 分钟。
  • 其他 HTTP 请求的超时时间为 1 分钟。
HTTP 请求和任务队列任务为 24 小时。如果您的应用未在此时间限制内返回请求,则 App Engine 会中断请求处理程序并发出错误以供代码处理。

基本扩缩的实例可以选择处理 /_ah/start 并执行程序或脚本数小时,而不返回 HTTP 响应代码。

与基本扩缩相同。
后台线程 不允许 允许 允许
驻留 实例根据使用模式关停。 实例根据 idle_timeout 参数关停。如果某个实例处于空闲状态(例如,在超过 idle_timeout 的时间内未收到请求),则系统会将该实例关停。 实例会保留在内存中,而状态会跨请求保留。停止实例时,日志中会显示 /_ah/stop 请求。 如果存在 /_ah/stop 处理程序或已注册的关停钩子,其在关停之前有 30 秒的时间完成运行。
启动和关停 实例在需要处理请求时创建,在空闲时自动关停。 实例会在需要处理请求时创建,在空闲时自动关停(由 idle_timeout 配置参数决定)。手动停止的实例在被强制终止之前有 30 秒的时间来完成请求处理。 App Engine 以向 /_ah/start 发出空白 GET 请求的形式自动向实例发送启动请求。和基本扩缩一样,手动停止的实例在被强制终止之前有 30 秒的时间来完成请求处理。
实例可寻址性 实例是匿名的。 服务“s”的“v”版本“i”实例可通过以下网址寻址:https://i-dot-v-dot-s-dot-app_id.REGION_ID.r.appspot.com。如果您为自定义网域设置了通配符子网域映射,则还可以通过 https://s.domain.comhttps://i.s.domain.com 格式的网址,针对服务或其任何实例进行寻址。您可以安心地在每个实例中缓存状态,并可在后续请求中检索此状态。 与基本扩缩相同。
扩缩 App Engine 会根据处理量自动扩缩实例数。这种扩缩会将在配置文件中基于版本提供的 automatic_scaling 设置考虑在内。 通过在 basic_scaling 设置的 max_instances 参数中指定实例数上限来配置使用基本扩缩的服务。活跃实例数会随着处理量的变化而变化。 您可以在该服务的配置文件中配置每个版本的实例数。实例数通常与内存中保存的数据集大小或离线工作吞需要的吐量相对应。您可以使用 Modules API set_num_instances 函数快速调整手动扩缩版本的实例数,无需停止当前正在运行的实例。

扩缩动态实例

使用基本扩缩或自动扩缩的 App Engine 应用可在给定时间由任意数量的动态实例提供支持,具体取决于传入请求的数量。随着对应用请求的增加,动态实例的数量可能也会增加。

使用基本扩缩的应用

如果使用基本扩缩,App Engine 会尝试保持较低费用,即使随着传入请求数量的增加,可能会导致更长的延迟时间。

如果没有任何现有实例可用于处理传入请求,App Engine 会启动一个新实例。即使在启动新实例后,某些请求可能需要排入队列,直到新实例完成其启动过程。如果需要尽可能减少延迟时间,请考虑使用自动扩缩,它会预先创建新实例以尽量减少延迟时间。

使用自动扩缩的应用

如果使用自动扩缩,则应用中的每个实例都有自己的传入请求队列。在队列变得足够长,对应用的延迟时间造成显著影响之前,App Engine 会自动创建一个或多个新实例来处理不断增加的负载。

您可以配置自动扩缩的设置,以便在理想性能与可能产生的费用之间找到一个最佳平衡点。下表介绍了这些设置。

自动扩缩设置 说明
目标 CPU 利用率 设置 CPU 使用率阈值,达到此阈值后,系统将启动更多实例来处理流量。
目标吞吐量利用率 设置并发请求数的吞吐量阈值,超出此阈值后,系统将启动更多实例来处理流量。
并发请求数上限 设置在调度器启动新实例之前,实例可以接受的最大并发请求数。

您可以观看 App Engine 调度程序设置视频,以了解这些设置的效果。

缩减

当请求数量减少时,App Engine 会减少实例数量。这种缩容有助于确保应用的所有当前实例都能实现最佳工作效率和成本效益。

当应用完全空闲时,App Engine 会关闭其关联的动态实例,但可以在必要时立即重新加载这些动态实例。重新加载实例可能会导致加载请求,并因此造成用户的延迟时间增加。

您可以指定空闲实例数下限。根据请求数量为应用设置适当数量的空闲实例,这让应用能够以极短的延迟时间处理每个请求,遇到请求数量异常高的情形时除外。

自动扩缩中的缩容

如果您的应用使用自动扩缩功能,则空闲实例在处于非活跃状态大约 15 分钟后便会开始关停。如需让一个或多个空闲实例保持运行状态,请将 min_idle_instances 的值设置为大于或等于 1

扩缩和批量请求

如果向服务发送批量请求(例如,发送到任务队列进行处理),则系统会快速创建大量实例。如果可能,我们建议通过限制速率(也就是限制每秒发送的请求数)来控制这一过程。例如,如果您使用 Google Tasks,则可以控制任务的推送速率

实例生命周期

实例状态

自动扩缩服务的实例始终处于运行中。但是,手动或基本扩缩服务的实例可能正在运行中或已停止。同一服务和版本的所有实例都具有相同的状态。您可以通过管理版本来更改实例的状态。您可以:

启动

收到启动请求(向 /_ah/start 发出的空白 HTTP GET 请求)时,系统会通过创建服务实例来做出响应。App Engine 会发送此请求以创建实例;用户无法向 /_ah/start 发送请求。手动扩缩和基本扩缩实例必须先响应启动请求,然后才能处理其他请求。启动请求可用于以下两个目的:

  • 启动无限期运行的程序,不再接受其他请求。
  • 在实例接收其他流量前对其进行初始化。

手动扩缩、基本扩缩和自动扩缩实例的启动方式有所不同。当您启动手动扩缩实例时,App Engine 会立即向每个实例发送 /_ah/start 请求。当您启动基本扩缩服务的实例时,App Engine 允许它接收流量,但直到实例收到它的第一个用户请求之后,App Engine 才会向其发送 /_ah/start 请求。只有在必要时才会启动多个基本扩缩实例,以处理增加的流量。自动扩缩实例不会收到任何 /_ah/start 请求。

如果某个实例以 HTTP 状态代码 200–299404 响应 /_ah/start 请求,系统会认为该实例已成功启动,可以处理其他请求。否则,App Engine 会终止该实例。手动扩缩实例会立即重启,而基本扩缩实例仅在需要处理流量时才会重启。

关停

关停过程可能由各种计划内和计划外事件触发,例如:

  • 实例过多,而应用请求(流量)不足。
  • 手动停止实例。
  • 将更新的版本部署到服务。
  • 实例超过其配置的 instance_class 的最大内存。
  • 应用的实例小时数配额用尽。
  • 实例被移到其他机器,原因可能是当前运行该实例的机器重启,或者 App Engine 转移您的实例以改善负载分布情况。

如上文缩减部分所述,App Engine 标准环境中的“只为需要的服务付费”平台所提供的一个好处是,系统会在没有流量时自动将实例数量缩减至零。这使得 App Engine 能够为无需持续接收请求的小型应用提供经济实惠的解决方案。当需要关停某个实例时,新传入该实例的请求将被路由到其他实例(如果有),而对于当前正在处理的请求,系统则会等待其完成。

当需要关停实例时,App Engine 会发送 KILL (SIGKILL) 信号,从而终止实例。

加载请求

当 App Engine 为您的应用创建新实例时,该实例必须先加载处理请求所需的所有库和资源。这一过程在首次向实例发送请求期间发生,称为“加载请求”。在加载请求期间,您的应用会进行初始化,导致此类请求需要更长时间才能处理完毕。

以下最佳做法可让您缩短加载请求的时长:

  • 仅加载启动所需的代码。
  • 尽可能少访问磁盘。
  • 在某些情况下,从单个 zip 或 jar 文件加载代码比从许多个单独的文件加载代码速度要快。

预热请求

预热请求是特定类型的加载请求;预热请求会在发出任何实际请求前将应用代码加载到实例中。手动扩缩实例或基本扩缩实例不会收到 /_ah/warmup 请求。

如需详细了解如何使用预热请求,请参阅配置预热请求

实例正常运行时间

App Engine 会尝试保持手动和基本扩缩实例无限期运行。但是,目前无法保证手动和基本扩缩实例的正常运行时间。 硬件或软件故障可能会毫无征兆地出现,导致实例提前终止或频繁重启,这些故障可能需要花费相当长的时间才能解决;因此,您应该以能够承受这些故障的方式构建应用。

以下实用策略可帮助您避免因实例重启带来的停机时间:

  • 减少重启实例或启动新实例所需的时间。
  • 对于长时间运行的计算,应定期创建检查点,确保您可以从该状态继续。
  • 您的应用应该是“无状态”的,实例上不存储任何内容。
  • 使用队列来执行异步任务。
  • 将实例配置为手动扩缩时,需执行以下操作:
    • 在多个实例间使用负载均衡。
    • 除了处理正常流量所需的实例以外,再多配置一些实例。
    • 编写回退逻辑,以便在手动扩缩实例不可用时使用缓存结果。

NTP 与 App Engine 标准环境

App Engine 标准环境具有使用 Google NTP 服务器的网络时间协议 (NTP) 服务。但是,NTP 服务不可修改。