1. 这笔账为什么越算越多
聊到 GCP 成本优化,我先说个不少人遇到过的真实场景——项目上线的时候 everyone 都盯着功能和稳定性,没人管账单。等一个季度结束,财务把账单甩过来,才发现光 Compute Engine 就烧掉几万块,里面还躺着一堆从未访问过的静态 IP、几个月没跑过的 Dataflow 任务、配置成 32 核高内存的 Jenkins 从节点。这时候你打开 GCP Console 的 Billing Report,面对一堆散发着金钱味道的数字,第一反应大概率是:这钱到底花哪去了?
我接手过的好几个团队都经历过这个阶段。问题不在于 GCP 本身定价高,而在于它给的默认配置太“慷慨”了。一个新项目,向导里默认就是 n2-standard-4,再顺手开个 premium tier 网络,挂个静态 IP,存储桶设成 multi-region,快照保留 180 天——项目就这么在每个月的账单上多付 20% 到 40% 的冤枉钱。这不是个别现象,我见过太多团队把云厂商的“默认值”当成了“推荐值”,而实际上默认值是为“不差钱、图省事”的用户准备的。
这轮我结合自己在几个业务线实际降本的经历,把 GCP 成本优化的路径拆开讲清楚。这篇文章适合正在被 GCP 账单困扰的运维、后端开发、技术负责人阅读,也适合准备把业务迁到 GCP 但还没想明白预算结构的朋友。里面给的思路和操作,都是可以直接照着做的,不是我纸上谈兵。
在动手之前,你得先接受一个认知:GCP 成本优化不是一次性动作,而是一套持续运行的机制。它由四个环节组成——看清楚钱花在哪,压掉不该花的钱,把必须花的钱花得更聪明,最后建立规则让浪费不再反弹。下面我按这个顺序逐一展开。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 先搞清楚钱到底花在哪——账单数据是一切优化的前提
2.1 不要凭感觉判断,先把账单导出变成习惯
很多团队的优化刚开始就做错了方向。他们不看自己账单明细,直接照着网上的“十大省钱技巧”逐条试。今天关掉几个实例,明天删除几个快照,看起来做了很多动作,月底一看账单,节省效果像在游泳池里倒了一杯水。原因很简单——没搞清楚自己资源消耗的“大头”是哪些,做的全是边缘优化。
正确路径是把账单先结构化。GCP 提供了一个基础能力叫 BigQuery Billing Export,你在 Billing Account 里开启这个导出,GCP 会每天把所有的计费明细写入你指定的 BigQuery dataset。每条账单记录包含项目 ID、服务名称、SKU、资源 ID、region、标签、使用量和价格,粒度细到每个实例的每小时的运行费用。
我已经把这一步视为任何成本优化工作的起点。没有这个数据底座,你后面做的所有分析都是盲人摸象。开启方式不复杂:进入 GCP Console 的 Billing,找到你的 Billing Account,左侧菜单里选 BigQuery Export,然后选择导出表类型。建议同时开启“Detailed usage cost”和“Detailed usage cost with resource-level annotation”两种导出,后者会额外包含 resource-level 的信息,对后续定位高消耗资源极其有用。
这个动作做完后,你需要做的就是等待数据积累。我建议至少积累 7 天再开始做分析,如果有 30 天的数据就更理想,能看出趋势和周期。
2.2 学会用几个基础 SQL 摸清费用结构
数据进 BigQuery 以后,如果你不懂怎么查,那这个导出配置等于白做。我在这里给几个每一次做成本分析都会用到的查询模板,你可以直接抄。
第一类:按项目归因,找出费用占比最高的几个项目。
sql复制SELECT
project.name AS project_name,
ROUND(SUM(cost), 2) AS total_cost
FROM
`project_id.billing_export.gcp_billing_export_v1_XXXXXX`
WHERE
invoice.month = '202506'
GROUP BY
project.name
ORDER BY
total_cost DESC
第二类:按 SKU 归因,快速定位哪些服务类型烧钱。这一条很有用,因为很多时候问题不在某个项目,而在某类资源,比如所有项目里的 Cloud SQL 实例加起来费用惊人。
sql复制SELECT
service.description AS service_name,
sku.description AS sku_name,
ROUND(SUM(cost), 2) AS total_cost
FROM
`project_id.billing_export.gcp_billing_export_v1_XXXXXX`
WHERE
invoice.month = '202506'
GROUP BY
service_name, sku_name
ORDER BY
total_cost DESC
LIMIT 50
第三类:按标签归因。前提是你在创建资源时加了标签,如果你的资源没做标签,这步要先补上,后面我会专门讲标签治理。
sql复制SELECT
labels.key AS label_key,
labels.value AS label_value,
ROUND(SUM(cost), 2) AS total_cost
FROM
`project_id.billing_export.gcp_billing_export_v1_XXXXXX`,
UNNEST(labels) AS labels
WHERE
invoice.month = '202506'
GROUP BY
label_key, label_value
ORDER BY
total_cost DESC
LIMIT 50
这套查询我就不展开讲 BigQuery 的语法细节了,可以把这几条 SQL 存成视图或计划查询,每天早上定时跑一次,把结果推到钉钉或 Slack。团队里每个人打开手机就知道昨天的钱主要烧在哪些地方,这种持续的感知比任何季度复盘都管用。
2.3 添加标签和建立项目分层体系
我发现自己团队里很多人对标签有误解,以为标签是给资源做分类用的,加上以后方便管理。实际上标签在这套体系里的作用是“财务归属追溯”,它能让每个团队、每个业务线发现自己名下有多少资源在跑、花了多少钱。
在 GCP 中,标签作用于绝大多数资源,格式是键值对,比如 cost-center: data-platform、owner: payment-team、env: staging、app: recommendation。你在创建资源的时候顺手就能打上去。麻烦的是历史资源,已经建好的实例、存储桶、磁盘全都是“无标签”状态。这时候需要写脚本用 API 遍历补齐,工作量不大,但对存量资源补充标签是很关键的。
项目分层也是一个容易忽略的点。我见过不少团队把研发环境、测试环境、灰度环境和生产环境全塞在同一个项目里,结果想按环境划分预算时,发现没有这个维度可切。GCP 的一个项目对应一个信任边界,也天然适合作为成本核算的单位。我的建议是至少按环境把项目拆开,prod、staging、dev 各建独立项目,每个项目拥有独立的预算告警。这样做的好处不仅在于成本管理清晰,权限控制也顺手做了加固。
2.4 设置多层预算告警,别等账单出来才心碎
预算告警这个功能没有技术难度,但它的价值被严重低估了。GCP 的 Billing Budget 可以针对 Billing Account 或具体项目设置月度预算,在消费达到预算的 50%、90%、100% 时触发通知,可以接入邮箱,也可以通过 Pub/Sub 转发到企业微信或钉钉机器人,实现实时告警。
我的实践经验是设置三层告警——第一层设为月度预算的 50%,起到提示作用;第二层设为 80%,这时候需要开始留意;第三层设为 100%,触发时说明这个月已经超支,需要立刻审视有没有异常消费。
有一些团队不屑于做这种“表面功夫”,觉得预算告警是给财务看的。但我个人建议把它纳入日常监控体系,毕竟异常费用若等到月底账单出来才看到,可能已经白白多花了十几天的钱。有一次我在某个客户那边排查费用突增,通过预算告警发现某个开发环境的实例在夜里 2 点被自动扩缩容到 20 台,连续跑了 5 天,如果没有预算告警在 80% 阈值时触发,这笔钱可能到月底才会引起注意。
3. 把不该花的钱压掉——闲置资源清理是见效最快的动作
3.1 别小看那台“开着没跑”的虚拟机
Compute Engine 通常是 GCP 账单上最显眼的一项,也是最容易产生浪费的一项。我做成本优化调研时,一项常见发现是一个团队开了几十台高配 VM,实际利用率常年不到 10%,甚至有些机器从上个月创建后就没有人登录过。
如果只是开着 VM 不用,费用已经浪费了。更隐蔽的是,很多人“关停”实例时选的是 Stop,而不是 Delete。Stop 确实会停止计算资源的计费,但附加在实例上的永久性磁盘、静态 IP、快照可能还在计费。许多团队关停了实例,想着以后还要用,结果磁盘和 IP 一直留着,每个月照样产生费用。还有不少有状态服务没有在 GCP 上做高可用,如果误删了实例,配置全丢,这也是许多团队不敢轻易 Delete 闲置 VM 的原因。
我自己处理这类问题的标准动作是:通过上一节提到的 BigQuery 账单数据,筛选出 compute engine 相关费用,按照资源 ID 聚合,找到金额靠前的实例,再用 Cloud Monitoring 检查这些实例的 CPU、内存、网络流量的实际利用率。对于连续 14 天 CPU 平均利用率低于 5% 的实例,基本可以认定为闲置资源。
处理闲置资源,我建议用以下三步走方案:
- 第 1 步:先 Stop,别急着 Delete。停止后观察一周,确认没有告警、没有用户反馈、没有依赖报错。
- 第 2 步:一周后,审视该实例的磁盘快照策略。建议先做一次完整备份,然后再 Delete 实例。Delete 时注意选择“同时删除关联的永久性磁盘”,否则磁盘会残留,继续产生存储费用。
- 第 3 步:确认关联的静态 IP 也释放掉。GCP 的静态 IP 即使没有绑定任何实例或转发规则,只要被分配了就会产生费用。一个 us-central1 区域的不使用静态 IP,每个月大约需要支付 7 到 8 美元,几十个 IP 加起来也不少了。
3.2 存储费用是温水煮青蛙,通常比想象中猛
存储费的浪费和计算资源不一样,它不是一下子突增的,而是不知不觉累积起来的。你可能觉得 Cloud Storage 每 GB 每月才 0.02 美元(标准存储),没多少钱。但如果你有 10 TB 的“祖传数据”躺在那,没人访问,每个月也要支付 200 多美元的存储费。更别提那些设置成 multi-region 的存储桶,如果实际访问量并没那么大,费用直接翻倍。
处理存储成本,我有一套固定的排查流程。先打开 Cloud Storage 界面,对每个 bucket 检查它的存储类别和位置。如果你的业务访问范围集中在单一区域,把 multi-region 改成 dual-region 或 single-region,能省下可观的费用。再运行存储生命周期管理策略,对 30 天前创建的、访问频率低的对象自动降级到 Nearline,90 天后降级到 Coldline,365 天后降级到 Archive。这个降级策略在 GCP 上是免费配置的,设置好之后它对 bucket 内的对象自动生效。
我见过一个比较夸张的例子。某个团队的一个 bucket 里存放的是日志备份,由于业务上要求日志保留 3 年,他们一直没有清理。这是一个基础数据积累形成的存储,不符合“闲置资源”的概念。通过对这个 bucket 设置了生命周期规则,把 180 天前的日志自动转为 Coldline 存储,他们每个月的存储费下降了大约 75%。如果这些日志允许只保留一年,使用 Archive 存储,费用还有进一步下降的空间。
永久性磁盘的快照也是存储费里比较容易被忽略的部分。GCP 的快照是增量快照,不是每次全量备份,但每份快照都会保留数据块。每隔一小时打一次快照、保留 180 天,数据量累积起来非常可观。我处理过一个账单里快照费用占总体费用 15% 的客户。后来把快照频率调整为每天一次、保留 7 天,费用瞬间降了下来。你得先想清楚:你对快照的需求到底是什么?大多数业务场景下,保留最近 7 天的日级快照,用来应对误删和故障恢复,已经足够了。
3.3 网络流量费常常被忽视,却悄悄吃掉利润
网络费用在 GCP 的成本结构里是个隐蔽项,很多团队甚至不看这一项,因为实例费用、存储费用的数字太显眼了。但一旦业务量上来,网络费用占比会越来越大。
GCP 网络计费有几个关键点你需要知道。同一个实例上不同内部 IP 之间的访问走的是内部网络,费用极低;而同 zone 内、同 region 内的流量通常免费或接近免费;真正烧钱的是跨 region 的流量、访问公网的 egress 流量。
架构上的调整往往能显著优化这部分费用。如果你有多个服务在不同 region 间频繁交互,考虑是把服务集中部署在同一 region,或者使用 VPC Peering 来降低流量成本。如果你的业务是下载大文件、视频流媒体之类的高带宽场景,可以考虑使用 Cloud CDN 做边缘缓存,让流量在边缘节点就被命中,避免每次都回源到中心 region。Cloud CDN 本身也有费用,但在高带宽场景下,它通常能帮你省更多。
这里有一个容易踩的坑:GCP 默认给每个实例分配公网 IP。如果你的实例不需要被公网直接访问,不要给它分配公网 IP,或者通过 Cloud NAT 做统一出网。很多安全团队为了防护,严格限制入站流量,却放任每个实例都带着一个公网 IP,这样既产生了额外的 IP 费用,也扩大了攻击面。
4. 把必须花的钱花得更聪明——选型、规格与付费方式
4.1 摸清工作负载的规律,按需选择实例类型
清理完闲置资源后,剩下还在运行的工作负载,是时候审视它们的配置是不是“超标”了。这是一件更精细的活,需要结合业务特征来选型。
GCP 的 Compute Engine 提供了多种系列,通用型(N2、N1)、计算优化型(C2、C3)、内存优化型(M1、M2)、高性能计算型(H3)等。每个系列下面还有不同的 vCPU 和内存配比。选择哪款的核心依据是业务对 CPU、内存的真实需求。
我见过一个内存型应用跑在 N2 实例上,给它配了 16 核 64 GB。从监控上看,CPU 平均利用率只有 3%,但内存占用一直维持在 50 GB 以上。这就是典型的配置选错,应该换成 M3 系列,用 8 核 128 GB 的配比,或者是 N2D 系列,在 AMD 平台上用内存优化配比,价格跟原来的配置几乎一样,性能反而更适配。这类“用监控数据反推规格”的操作,每个有成本优化诉求的团队都应该做。
还有一类很典型的工作负载是“短时高峰型”——比如定时跑批任务,每天深夜跑两个小时,白天完全闲着。对这种负载,用按需实例全天候跑,等于为一天里其余的 22 个小时付了钱。更好的选择是把定时批处理任务迁移到 Cloud Run Jobs 或 Cloud Batch,它们按实际运行时间计费。我之前把一个团队的支付对账任务从常驻 VM 迁到 Cloud Run Jobs,费用降了大半——迁移前是一个月 24 小时常驻,迁移后是每天只跑 30 分钟。
4.2 Commit 与 Spot,两种不同方向的省钱方式
GCP 购买层面有两条主流省钱路径,这两条路径分别适用于不同类型的工作负载。
第一类是 Committed Use Discounts(CUD)。你可以用 1 年或 3 年的承诺换取对应资源的折扣。内存优化型实例的承诺使用折扣通常能达到 40% 到 50%,通用型也有 20% 到 40% 的折扣。CUD 分为 resource-based 和 spend-based 两种。Resource-based 要求你承诺特定的机器系列和 region,比如 us-central1 的 n2-standard-8,承诺后无论你实际开多少台,都需要为承诺的 8 核支付费用。Spend-based 则灵活得多,你只需承诺一个每小时的最低消费金额,任意服务都可以抵扣,适合业务不完全稳定、又确定长期会使用 GCP 的场景。
CUD 适合的是明确会长期运行的稳定负载,比如生产环境的数据库、核心 API 服务。把这类负载的账单梳理出来,如果能确认未来一年到三年都会持续使用,买 CUD 基本是无风险的省钱动作。计算一下每月的基线消费,如果数字够大,直接买 spend-based 的 1 年或 3 年承诺,折扣会体现在后续每月的账单中。这三五年下来,节省量相当可观。不过承诺前需要仔细考量,因为 CUD 是提前的资本开支,承诺了就不能反悔。
第二类是 Spot 实例。很多人把 Spot 和抢占式实例搞混,GCP 的 Spot 实例本质上就是原来的 preemptible 实例,折扣力度通常在 60% 到 80%,但 GCP 随时可能因为资源紧张而回收它们,所以这类实例只适合做无状态、可容错、能随时重启的工作负载。例如数据处理任务、渲染任务、CI 跑测试的 node,这些任务即使中断,重新排队跑一遍就行,几乎没有损失。
我之前做过一次调整,把一个数据管道集群的固定 20 台实例改成“10 台 CUD + 10 台 Spot”的组合。CUD 负责保证管道的底线吞吐,Spot 负责处理高峰期突发。这样改完,整个集群的成本下降了接近一半。如果你是跑在 GKE 上的业务,可以考虑开启 Node Auto-Provisioning 里的 Spot 节点池,让 Kubernetes 自动在 Spot 上调度那些适合的 Pod。
4.3 GKE 资源请求和自动扩缩容,是 K8s 成本的核心控制阀
如果你的业务跑在 GKE 上,成本优化的逻辑跟纯 VM 有所不同。GKE 的计费有三层——集群管理费(每集群每小时 0.10 美元)、节点费用(实际上就是 Node 所在的 VM 费用)、以及可选的附加组件费用(如 Cloud Filestore、Cloud Logging 等)。在 GKE 场景下,最重要的优化点在于控制节点数量和节点规格。
要控制节点数量,首先要确保容器层面的资源请求(requests)设置得合理。Kubernetes 调度 Pod 时,看的不是 Pod 实际使用量,而是它声明的 requests。如果一个 Pod 实际只用 200 毫核 CPU,但声明了 1 核,那节点上会为它预留 1 核的空间,其他的 Pod 就挤不进来,节点只能白白多开。我看到很多团队的资源请求是照着经验填的,一填就填很高,原因是对性能的担忧,属于可以理解的保守心态,但成本上浪费了。进入生产前,要至少跑一周,观察 Pod 的实际使用量,再把 requests 调整到贴近实际值,这样能显著提高节点装箱率。
另一个关键点是用好 Cluster Autoscaler 和节点池的自动伸缩配置。我处理过一个客户的 GKE 集群,高峰时 30 个节点,低峰时只有 5 个节点在跑。由于他们没有配置 Cluster Autoscaler,Pod 再怎么少,节点也始终维持在 30 个。开启 Cluster Autoscaler 以后,低峰自动缩到 5 个,成本直接随时间曲线下降。在此基础上还可以配合我刚才说的 Spot 节点池,让那些适合的 Pod 调度到 Spot 上,进一步把成本压下来。
如果集群的规模比较大(比如说超过 50 个节点),可以考虑把节点类型切换成 Tau T2D 或 T2A,它们是 GCP 专门为高并发、可横向扩展的工作负载设计的性价比型处理器。这两个系列的价格比 N2 系列低不少,如果业务没有特别依赖某些高级 CPU 指令集,T2D 往往能省下一大块成本。
4.4 Cloud SQL、BigQuery 等托管服务也有降本空间
托管服务容易被忽略,因为它们是一键开通的,很多人开通后就再也不看配置了。
以 Cloud SQL 为例,一个常见的场景是:开发环境开了一个 db-n1-standard-2 的实例,7×24 小时运行。开发环境白天大家用得频繁,晚上和周末基本闲着,实例运行产生的费用却一点没少。如果能接受开发环境晚上关闭,可以设置一个定时任务,日落时停实例,日出时开实例。Cloud SQL 在停止状态时不收取计算费用,只收取存储费用。一个开发环境的数据库这样做,一个月能省下约 70% 的成本。
对于生产环境的 Cloud SQL,可以关注高可用配置和读写分离。如果现有架构只有一个主实例,还没有做高可用,实际上 GCP 会为高可用配置额外收取备实例的费用。这是有必要的成本,但要注意备实例只用于故障切换,不应该被业务把读流量打到上面。另一个思路是如果读流量特别大,单独开只读实例,并把主实例的规格降低,整体成本往往比一个大主实例硬扛所有流量更低。
BigQuery 的成本优化是个大话题,我提几个最关键的点。第一,BigQuery 是按扫描的数据量计费的,控制查询扫描量就控制了成本。给表做分区和聚簇,是减少扫描量的最有效手段。第二,使用物化视图来缓存重复查询的结果,而不是每次跑原始数据。第三,如果业务有大量固定的报表查询,可以考虑购买 BigQuery 的 flat-rate 容量,按月付费,而不是按扫描量付费。这个决策要看查询量的规模,不能盲目套用。我见过一个团队每月查询 500 TB 的数据,按需计费花费巨大,后来改成了 flex slot 的方式,费用降了一半以上。
5. 自动化治理与持续运营,建立不让浪费反弹的机制
5.1 用 Terraform 管理资源,把成本检查写进 IaC 流程
前面说的很多优化动作,本质上都是一次性的“抢救”行为。如果团队的资源创建流程不改变,浪费很可能在一两个月后悄悄反弹回来。要根治这个问题,最有效的办法是把成本治理的左移,融入到资源创建的代码流程中。
如果你的团队已经在用 Terraform 管理 GCP 资源,那可以考虑在 CI 阶段加入成本检查。举例来说,在 Terraform 的 plan 阶段用 infracost 这个开源工具解析出此次变更会新增或减少多少费用。它支持 GCP,在 pull request 里自动评论,写明“这次变更预计会多花多少钱”。有了这个反馈,开发者在创建大规格资源之前就能看到费用预期,而不是等月底账单出来才知道。
另一个思路是用 Terraform 的 policy 强制约束资源创建。举例:用 gcloud beta terraform vet 结合约束模板,禁止创建超过 X 核数的实例,强制要求所有 Compute Engine 实例必须打上 owner 和 cost-center 标签,禁止创建 multi-region 存储桶。这些策略可以在资源创建那一刻就拦截掉不符合成本规范的操作,比事后发现再纠正要高效得多。我这里想强调的是,“成本规范”和“安全规范”应该一样被对待,写进代码审查和 CI 流程里,而不是只依靠开发者的自觉。
5.2 如何用 Cloud Functions 做定时清理和停机
自动化定时清理是一个适合脚本化解决的场景。GCP 里的闲置资源是动态产生的——新项目上线时会创建很多资源,项目下线后这些资源并没有自动消亡。所以要写一些定期的巡检脚本来保障环境整洁。
我的定时清理脚本通常用 Cloud Scheduler + Cloud Functions 或 Cloud Run 来实现。Cloud Scheduler 每天触发一次函数,函数内调用 GCP API 列举出所有符合条件的资源,然后做处理。举几个常见的场景例子:
第一个是自动停止非生产环境的 VM。根据标签过滤出 env=dev 或 env=staging 的实例,在每天晚上 8 点执行 Stop,早上 7 点执行 Start。注意 GCP 的 API 是支持批量操作的,写循环遍历项目列表,就能管理多个项目下的实例。
第二个是自动清理不用的静态 IP。列举出所有静态 IP,检查它们的 status 是否是 RESERVED(即没有绑定到任何转发规则),如果状态持续保留超过 7 天,就自动释放。这个脚本需要保留足够长的时间窗口,避免误删还在使用的 IP。
第三个是清理过期的临时资源。如果你的团队会用 GCE 创建临时测试机,可以要求创建时附带一个 expire-at: 20250801 的标签。巡检脚本读取当天日期,把超过 expire-at 日期的实例自动删除。这个方法配合前面提到的预算告警,能迅速看到效果。
整体来看,我建议团队内部每季度做一次全面的 FinOps 巡检。这项工作固定在一个月中的某一天执行,把资源清单导出,检查是否有长期运行的低利用率实例、是否有未清理的快照、是否有新的费用增长点。这样确保问题不会积累到不可收拾的地步。
5.3 让每个团队看到自己的成本数据并为之负责
在技术层面之外,我还想强调一个容易被忽视的治理层面问题:成本优化不应该只是运维或基础设施团队的独角戏,它必须落到每个研发团队头上。
我处理过一个很典型的案例。某业务线有一个“数据同步服务”,每个月在 GCP 上的花费占全公司的 26%,但负责该服务的研发团队从未意识到这一点,因为账单从来不会直接出现在他们的工作视野中。过去他们优化过服务的延迟和稳定性,但对成本一无所知。
后来我们做了两件事:第一件,通过前面提到的标签体系,让每个业务的账单可以按服务维度区分;第二件,把月度成本报表主动推送给对应的团队负责人,在内部建立一个“成本排行榜”。榜单显示的不是“谁花钱最多谁丢人”,而是“谁的每万次请求成本最低”和“谁的环比增长异常”。这种做法让成本和业务指标挂钩,团队在优化代码和配置时,就自然而然地把成本因素纳入考量。
这里我用一个浅显的类比来解释为什么监控成本重要:驾驶汽车时,如果仪表盘上省掉了油量表,你会在一个不确定的时刻突然停在路上。成本监控就是云资源的油量表,它需要常驻、灵敏,而不是等到每个月月底才被动看一次。
6. 实战复盘——从月账单 12 万降到 5.5 万的全过程
6.1 第一阶段的账单分析与归类
为了让你对前文提到的优化手段有更整体的把握,我分享一个之前做过的完整优化案例。这是一家做在线教育平台的中型团队,GCP 月账单大约在 12 万美元。业务主要部署在 GKE 上,使用 Cloud SQL 存业务数据,BigQuery 做离线分析。下面是我们第一阶段的分析结果。
第一步,从 BigQuery 账单导出表拉出过去三个月的数据,按服务归属做了聚合。费用分布大概是:
- Compute Engine(含 GKE 节点):占比 45%
- Cloud SQL:占比 18%
- BigQuery:占比 15%
- Cloud Storage 与快照:占比 12%
- 网络流量:占比 6%
- 其他(Cloud NAT、监控、日志等):占比 4%
这个结构很典型。计算、存储和管理服务是三大头。第二阶段我们在计算项里细挖,找出各个 GKE 节点池的实例规格和利用率。
6.2 分项执行了哪些降本动作
针对 Compute Engine 这一大头,我们做的事包括:首先通过监控数据,发现一个“数据同步节点池”的 CPU 平均利用率只有 8%,实例规格是 n2-standard-16。业务特征是跑定时任务,每天运行三到四次,每次大概持续 20 分钟。我们的方案是把这批任务迁移到 Cloud Run Jobs 上,临时跑一下,平时彻底休眠。这个调整直接让该项成本下降了约 90%。
另外,生产环境的两个 GKE 节点池(一个 n2-standard-8 池跑在线服务,一个 c2-standard-4 池跑 CI),我们做的优化是:在线服务池的 Pod 资源 requests 普遍偏高于实际使用量近一倍,我们根据监控数据把 requests 调整为贴近实际值后,节点数量从 18 台降到 12 台,依然扛得住原有流量。CI 节点池全部切换为 Spot 实例,并调整成按最多 10 台扩缩容。这一层合起来让单月的 GKE 相关费用下降了差不多 38%。
Cloud SQL 这边的优化有两块。开发环境的实例已经有测试库跑着,我们加了定时启停任务,每周一到周五早八点启动、晚七点停止,周末全天停止。这块成本下降了大概 65%。生产环境的 Cloud SQL 原先是一个 db-n1-standard-8,我们加了只读实例把读流量分担过来,主实例降配到 n1-standard-4,整体月费用下降了约 30%,而且查询性能反而更稳定了。
BigQuery 的优化主要围绕分区、聚簇和物化视图三个方面。业务方有大量的用户行为分析查询,查的都是最近 7 天数据,但表是全表扫描。我们把这些大表做了按天分区,查询习惯加上时间过滤条件,同时针对常用的日活、留存指标建了物化视图,查询扫描量断崖式下降。这个配合把 BigQuery 费用从月 1.8 万美元降到了 8000 美元左右。
存储方面,把四个 bucket 从 multi-region 改成 single-region,并配置了生命周期规则(30 天转 Nearline,90 天转 Coldline),快照策略改成每天一次、保留 7 天。整个存储费用下降了近 80%。
6.3 优化结果和后续保持机制
这几套组合拳打完后,这个客户的月度账单从 12 万美元降到了 5.5 万到 6 万美元之间,降幅超过 50%。需要注意的是,有一些优化动作(比如 CUD 购买)是在下一阶段才介入的,我们当时也根据剩余的稳定基线消费,购买了三年期的 spend-based CUD,每月再获得约 22% 的额外折扣。如果算上这部分,实际费用可以进一步降到 4.5 万美元左右。
后续的保持机制里,除了前面说的预算告警、标签、定期巡检外,我们还把 Terraform 的 Infracost 检查接入了他们的 GitLab CI,每次合并代码前都自动进行成本预估。这种做法持续运行了半年,期间没有再出现过明显的费用回弹。整个项目做下来的体会是,成本优化不是靠一次“大扫除”能完成的任务,需要持续治理和保持,而设置好工具和检查机制后,并不需要投入多少人力去维持效果。
7. 我的实操建议与经验心得
最后写几条我实操下来的心得,有些是踩过坑之后得出的教训,各位可以参考一下。
第一,操作前务必做好备份。无论你是要删除实例、清理快照还是关停数据库,都先确认备份策略是有效的。成本优化不应该以牺牲数据安全为代价。我见过有团队在清理快照时,误删了还在保留期内的唯一备份,后来需要恢复数据时追悔莫及。
第二,Spot 实例虽然便宜,但不要用在有状态服务上。如果你把数据库跑在 Spot 实例上,等 GCP 发来抢占通知的时候,你基本只能眼睁睁看着服务中断。如果想要低成本跑有状态服务,推荐的方法是使用 CUD 搭配适当的高可用架构。
第三,购买 CUD 之前先观察至少 30 天的消费曲线。用最近一个月的稳定消耗作为参考,买到合适的力度。别在业务刚上线、负载还在快速变化的时候贸然锁三年,如果业务量下降,你承诺的每小时消费就成为沉没成本了。
第四,从小处着手,别小看小费用的日积月累。一个闲置的静态 IP 一个月 7 美元、一个小磁盘的快照一个月 3 美元、一个多余的日志导出一个月 2 美元。这些单项费用单独看都不多,但几十个加在一起,就成了每个月数不清的浪费,积累一年,金额不容小觑。
第五,如果你要向上级汇报成本优化的进展,建议不要直接抛一堆技术名词,而是换算成更直观的指标:每一万次 API 请求的基础设施成本下降了多少、每月的账单总额趋势是怎么变化的。把成本优化和业务指标挂钩,能让整个事情获得来自业务方的理解和支持,也更方便后续治理的推动。
GCP 成本优化这件事,贵在坚持和认真。我每次看到一个团队在账单治理后,把省下来的预算投入到新的业务功能开发中,就觉得这件事做得特别值得。按照我上面讲的步骤一步步推进——先把账单数据看透,再清理闲置资源,接着优化选型和购买策略,最后建立自动化和持续治理机制——相信你也能把云上成本掌握在自己手里。
