2. 资源计量模型:把抽象的资源变成账单上的数字
做流批一体成本核算,第一关就是搞清楚——资源到底怎么量?
你想想看,一个 Flink 任务跑在 K8s 上,它吃了多少 CPU、占了多少内存、写了多少数据到 HDFS?如果没有一套统一的计量模型,你根本没法跟业务方说清楚“这个任务为什么花了 500 块”。
我个人习惯把资源计量拆成四个维度:计算、内存、存储、网络。每个维度都有它的计量单位和坑。下面我一个一个说。
2.1 计算资源计量:vCore-秒
计算资源是最好理解的——就是 CPU。但怎么计?按核数 × 时间。
我建议用 vCore-秒 作为基本单位。为什么不是 vCore-小时?因为流任务可能只跑了几分钟,甚至几十秒,按小时算太粗了。
公式: 计算资源消耗 = 分配的 vCore 数 × 运行时长(秒)
例如:一个任务分配了 4 vCore,跑了 3600 秒,消耗就是 4 × 3600 = 14,400 vCore-秒。
这里有个细节——分配 vs 实际使用。我在项目中遇到过,业务方说“我的任务只用了 20% CPU,凭什么按 4 核收费?” 嗯,这个问题很典型。
我的做法是:按分配计量,按使用优化。账单上写分配量,但优化建议里给实际使用率。这样既公平,又能推动业务方调整资源配置。
| 计量方式 | 优点 | 缺点 | 适用场景 |
|---|---|---|---|
| 按分配计量 | 简单、可预测 | 可能浪费 | 固定资源池、SLA 严格的任务 |
| 按实际使用计量 | 公平、精细 | 波动大、难预算 | 弹性伸缩、批处理任务 |
| 混合计量(推荐) | 兼顾公平与稳定 | 实现复杂 | 流批一体平台 |
我的小技巧: 在 Flink 的 Metrics 里直接暴露 taskmanager.numRegisteredSlots 和 cpu.usage,配合 Prometheus 采集,就能算出精确的 vCore-秒消耗。别信 K8s 的 request/limit,那玩意儿不准。
2.2 内存资源计量:GB-秒
内存比 CPU 贵,而且更敏感。你给少了,OOM;给多了,浪费。
计量单位我选 GB-秒。逻辑跟 vCore-秒一样:分配的内存(GB)× 运行时长(秒)。
但内存有个特殊的地方——堆内 vs 堆外。我记得有一次排查一个 Spark 任务,堆内内存只用了 2GB,堆外却占了 8GB,结果按总分配 10GB 计费,业务方炸了。
后来我定了个规则:堆内 + 堆外 + 元空间,全部计入。因为不管内存用在哪,它都占着物理资源,别人用不了。
避坑指南: 我曾经遇到一个 Flink 任务,Checkpoint 频繁导致 RocksDB 堆外内存暴涨,账单直接翻倍。后来加了 state.backend.rocksdb.memory.managed: true,才把内存控制住。所以计量模型里一定要能区分出“正常使用”和“异常抖动”的内存消耗。
2.3 存储资源计量:GB-小时
存储计量相对简单,但容易漏。我把它分成三类:
- 临时存储: 任务运行时的 shuffle 数据、中间结果。用完即删。
- 持久化存储: Checkpoint、Savepoint、Hive 表、HBase 等。
- 日志存储: TaskManager 日志、JobManager 日志、Metrics 数据。
计量单位用 GB-小时。为什么不是 GB-秒?因为存储是持续占用的,按秒计太细了,而且存储成本通常比计算低一个数量级,没必要那么精细。
公式: 存储资源消耗 = 存储空间(GB)× 占用时长(小时)
例如:一个 Checkpoint 占 50GB,保留了 24 小时,消耗就是 50 × 24 = 1,200 GB-小时。
这里有个容易踩的坑——重复计费。比如 Checkpoint 数据既存在 HDFS 上,又被备份到远端。我建议只计主存储,备份成本算到平台 overhead 里,不要摊到单个任务上。
2.4 网络 IO 计量
网络 IO 是最容易被忽视的。很多人觉得“内网传输不要钱”,但事实上,网络带宽是共享资源,流量大了会影响其他任务。
我建议计量两个维度:
- 入站流量(Ingress): 数据源读取、Kafka 消费、外部 API 调用。
- 出站流量(Egress): 结果写入、Kafka 生产、跨机房传输。
单位用 GB,按总量计,不按时间。因为网络 IO 是瞬时行为,按时间计没意义。
我的经验: 网络 IO 计量最难的是“归属”。一个任务从 Kafka 读数据,数据量 100GB,但这 100GB 是 Kafka 集群内部复制的,还是真的从网络传输的?我一般用 network.bytes.in 和 network.bytes.out 这两个 Metrics,配合 Prometheus 打点,基本能算清楚。
2.5 资源计量模型全景图
下面这张图把四个维度的关系画清楚了。你可以看到,计算和内存是“瞬时资源”,按秒计;存储是“持续资源”,按小时计;网络是“流量资源”,按总量计。
2.6 计量模型落地要点
最后说几个落地时的注意事项:
- 统一时间窗口: 所有维度的计量时间戳要对齐。我见过一个平台,计算按 UTC 时间,存储按本地时间,对账时差了 8 小时,查了三天才找到原因。
- 保留原始 Metrics: 不要只存聚合后的账单数据。原始 Metrics 至少保留 30 天,方便回溯和审计。
- 区分任务类型: 流任务和批任务的计量粒度可以不同。流任务按分钟聚合,批任务按作业粒度聚合。
- 考虑 Overhead: 平台本身的资源消耗(如 JobManager、调度器、监控组件)要单独计量,不要摊到用户任务里。
我曾经踩过的坑: 一开始我把所有 Overhead 按比例摊到每个任务上,结果一个只跑 5 分钟的小任务,账单里平台 Overhead 占了 80%。业务方直接投诉说“你们平台比我的任务还贵”。后来改成 Overhead 单独列支,按团队或项目维度分摊,才平息了争议。