PAYATHON 2026

Google App Engine Budget 和 Daily Spending Limit 未生效

支付阿杰

结论

你的设置本身没有问题,但无法限制 App Engine flexible environment 的实际费用:

  • **Budget 只用于监控费用和发送告警,不是硬性消费上限。**费用超过 $0.01 后,资源不会自动停止。
  • App Engine 的 Daily Spending Limit 不适用于 flexible environment 实例产生的 Compute Engine 类费用。
  • **Flexible environment 没有供实例每天自动恢复的免费 quota,通常还会保留至少一个运行实例。**即使没有请求,也会继续产生 CPU、RAM 和 Persistent Disk 费用。

因此,仅靠 Budget 或 Daily Spending Limit,无法做到”免费额度用完后自动停机”。如果开发环境不需要一直在线,可以停止 App Engine 版本、设置定时启停,或者改用能够缩容到零的运行环境。

为什么没有在 $0.01 时停止

Budget 只负责告警

Google Cloud Billing Budget 会跟踪支出,并在费用达到指定比例或预测金额时发送通知。它不会:

  • 拒绝新请求;
  • 停止 App Engine 实例;
  • 禁用项目计费;
  • 保证费用不超过预算。

预算数据还有统计延迟。即使通过预算通知触发自动化操作,停机前仍可能继续产生费用,所以不能将其视为精确的硬限额。

页面中的:

$7.25 / $0.01

表示预算范围内已统计到约 $7.25 的费用,并不表示系统承诺在费用达到 $0.01 时停止计费。

如果账单明细合计与预算页面不一致,可以检查:

  • Budget 是否覆盖整个 billing account,而账单明细只筛选了某个项目;
  • 是否存在其他 SKU、项目或服务;
  • 两个页面的日期范围是否一致;
  • 折扣、赠金、税费和未最终结算费用是否使用了不同的统计口径;
  • 费用数据是否仍在延迟更新。

Daily Spending Limit 不控制 Flex 资源

Daily Spending Limit 是 App Engine 的旧式限额机制,只适用于明确受其支持的 App Engine 资源。Flexible environment 实例使用的是底层计算、内存和磁盘资源,相关费用不会被这个限额可靠地截断。

账单中的以下项目,就是 Flex 实例持续运行产生的费用:

App Engine Flex Instance Core Hours
App Engine Flex Instance RAM
Google Compute Storage PD Capacity

所以,控制台即使显示:

Enabled (Daily spending limit: $0.01)

也不代表 Flex 实例会在消费达到 $0.01 时停止。

为什么没有请求仍然收费

Flexible environment 更像持续运行的虚拟机环境,而不是按请求启动的纯无服务器环境。只要版本处于 serving 状态,即使实例空闲,也可能继续占用:

  • vCPU;
  • 内存;
  • Persistent Disk;
  • 其他网络或存储资源。

自动扩缩容可以减少实例数量,但 Flex 通常无法缩容到零。默认实例数和可用配置可能随运行时及平台策略变化,具体应以当前项目控制台和官方配置说明为准。

你可以限制最大实例数,防止流量导致费用快速增长:

runtime: python
env: flex

automatic_scaling:
  min_num_instances: 1
  max_num_instances: 1
  target_cpu_utilization: 0.8

resources:
  cpu: 1
  memory_gb: 0.5
  disk_size_gb: 10

这种配置只能控制成本增长,不能让空闲成本降为零。资源字段还必须满足当前 Flex 运行时规定的最小值,部署前需要根据实际运行时检查配置。

开发期间如何停止计费

开发环境不用时,可以停止正在运行的版本:

gcloud app versions list

确认服务名和版本号后执行:

gcloud app versions stop VERSION_ID \
  --service=SERVICE_ID \
  --project=PROJECT_ID

需要继续开发时,可以重新部署版本:

gcloud app deploy app.yaml \
  --project=PROJECT_ID

也可以把流量切换到已有版本:

gcloud app services set-traffic SERVICE_ID \
  --splits=VERSION_ID=1 \
  --project=PROJECT_ID

停止前要确认该服务没有仍需处理的生产流量。版本停止后,账单可能因数据延迟而继续更新。已经产生的费用不会撤销,部分存储或其他独立资源也可能继续计费。

如果只是临时测试,可以在部署后使用,用完立即停止版本。也可以通过 CI/CD 或脚本封装部署和停止命令,省去每次进入控制台操作的步骤。

更适合”无人访问时零实例”的方案

如果应用兼容 App Engine standard environment,可以考虑迁移到 Standard。Standard 的自动扩缩容可以配置为无流量时缩容到零,例如:

runtime: python312

automatic_scaling:
  min_instances: 0
  max_instances: 1

Standard 和 Flex 在运行时、文件系统、系统依赖、请求时长及网络能力方面并不完全相同。迁移前要确认应用是否依赖:

  • 自定义 Docker 镜像;
  • 原生系统软件包;
  • Flex 特有的网络或后台进程能力;
  • 本地可写磁盘或长时间运行的请求。

Cloud Run 等其他可缩容到零的产品,也可能更适合临时开发服务。不过,数据库、静态 IP、磁盘和负载均衡器等外围资源仍可能单独计费。

能否根据 Budget 自动停机

可以通过以下链路实现近似的自动停机:

Cloud Billing Budget
        ↓
Pub/Sub budget notification
        ↓
Cloud Run function / Cloud Function
        ↓
停止 App Engine 版本或禁用项目计费

但这仍不是严格的消费上限,原因包括:

  • 预算数据和通知存在延迟;
  • 通知可能重复发送;
  • 停止资源需要时间;
  • 停止应用版本不一定会停止项目中的其他计费资源;
  • 禁用 billing account 或项目计费属于高风险操作,可能影响所有相关服务。

自动化处理程序应只获得必要的最小权限,并处理消息去重、阈值判断和失败重试。不要因为收到一次 Pub/Sub 消息,就直接关闭整个 billing account。

是否需要解除信用卡绑定

不建议把解除信用卡绑定当作日常成本控制手段。支付方式、billing account 和项目资源属于不同层次。移除支付方式并不等于以可控方式停止应用,还可能造成欠费、账户暂停或项目资源受限等风险。

更稳妥的处理顺序是:

  1. 停止当前 Flex 版本,并确认没有其他版本仍在接收流量。
  2. 在 Billing Reports 中按项目和 SKU 检查剩余费用的来源。
  3. 将 Flex 的最大实例数限制在开发所需的最小规模。
  4. 不需要常驻服务时,通过脚本或 CI/CD 停止版本。
  5. 如果必须自动缩容到零,迁移到 App Engine Standard 或 Cloud Run。
  6. 保留 Budget 告警用于监控,但不要将其当作费用熔断器。

问题不在于 $0.01 设置失败,而在于 Budget 和 Daily Spending Limit 原本就不是 Flex 资源的硬性费用上限。

备注:内容仅供参考。