3. 资源粒度与计价模型:Slot、Task Slot、Parallelism 与 vCore、GB-hour 的换算关系
聊实时特征的成本,绕不开一个核心问题:你买的资源,到底被用掉了多少?
Flink 里我们天天说 Slot、Parallelism,到了云平台账单上却变成了 vCore·小时、GB·小时。这两个体系之间的换算,说白了就是成本核算的「汇率」。搞不清楚这个,你做的成本分析就是一笔糊涂账。
我个人习惯把这件事拆成三层来看:物理资源层 → 调度单元层 → 计费计量层。下面我们一层一层剥开。
核心观点:Slot 是 Flink 的调度承诺,vCore/GB 是云平台的计费刻度。两者之间的换算系数,决定了你的真实资源利用率。
3.1 物理资源层:vCore 与 GB 到底是什么?
先看最底层。不管你是用自建机房还是云上托管,一台机器(或者一个 Pod)的核心指标就两个:CPU 算力和内存大小。
- vCore(虚拟核):云平台上 1 个 vCore 通常对应一个超线程。我遇到过不少团队把 1 vCore 当成 1 个物理核来算,结果资源预留严重不足。实际上,1 个物理核在云上通常对应 2 个 vCore。
- GB(内存):这个好理解,就是分配给 JVM 堆内 + 堆外的总内存。注意,Flink 的
taskmanager.memory.process.size包含堆内、堆外、网络缓冲、JVM Metaspace 等,实际可用堆内存会比这个值小 20%-30%。
我的经验:在云上选机型时,我习惯把 vCore:GB 比例控制在 1:4 到 1:8 之间。Flink 计算密集型的任务,1:4 就够了;状态大的任务,得上 1:8 甚至更高。比例选错了,要么 CPU 空转,要么内存 OOM。
3.2 调度单元层:Slot 与 Task Slot 的真相
Flink 的 Slot 机制,很多人理解有偏差。我直接说结论:Slot 不是 CPU 核,也不是内存大小,它是一个「资源占位符」。
TaskManager 启动时,会向 ResourceManager 注册自己有多少个 Slot。每个 Slot 能跑一个 SubTask。但 Slot 本身不绑定固定的 CPU 或内存配额——所有 Slot 共享 TaskManager 进程的全部资源。
举个例子:
# 一个 TaskManager 配置
taskmanager.numberOfTaskSlots: 4
taskmanager.memory.process.size: 8g
这个 TaskManager 有 4 个 Slot,总内存 8 GB。但每个 Slot 并没有被限制为 2 GB。如果某个 SubTask 吃掉了 6 GB,其他 3 个 Slot 就只能分剩下的 2 GB。这就是为什么 Slot 数设得太多,反而容易引发 OOM。
我曾经踩过的坑:有次把 Slot 数设成了 16,想着并行度拉满跑得快。结果一个 SubTask 状态膨胀,直接把整个 TaskManager 撑爆了。后来我学乖了:Slot 数 = 该 TaskManager 上期望的最大并行 SubTask 数,不是 CPU 核数。
3.3 并行度 Parallelism 与 Slot 的映射关系
Parallelism 是逻辑概念,Slot 是物理概念。它们之间的映射规则其实很简单:
- 一个作业的并行度是 N,就需要 N 个 Slot 来运行它的所有 SubTask。
- 如果集群总 Slot 数 < N,作业就提交不了,会一直等待资源。
- 同一个 Slot 可以运行不同算子的 SubTask(Slot Sharing),前提是它们属于同一个作业。
我画了一张图,帮你理清这层关系:
3.4 计费计量层:vCore·小时 与 GB·小时
到了云平台账单这里,计价单位变成了 vCore·小时 和 GB·小时。怎么算的?
vCore·小时 = vCore 数量 × 运行小时数
GB·小时 = 内存 GB 数 × 运行小时数
举个例子:你启动了一个 4 vCore、8 GB 的 TaskManager,跑了 2 小时。那么计费就是:
- vCore·小时 = 4 × 2 = 8 vCore·h
- GB·小时 = 8 × 2 = 16 GB·h
注意,这里不关心你实际用了多少 CPU 和内存。哪怕你的任务 CPU 利用率只有 10%,云平台也按你申请的 4 vCore 来收费。这就是为什么资源规格选大了,成本会白白浪费。
3.5 换算关系:从 Slot 到 vCore·小时
现在我们把三层串起来,看看完整的换算链路:
| 层级 | 单位 | 说明 |
|---|---|---|
| 物理资源 | vCore, GB | TaskManager 申请的容器规格 |
| 调度单元 | Slot | TaskManager 内可运行的 SubTask 数量上限 |
| 逻辑并行 | Parallelism | 作业的并行度,决定需要多少 Slot |
| 计费计量 | vCore·h, GB·h | 云平台按 TaskManager 规格 × 运行时长计费 |
换算公式可以这样写:
每个 Slot 的「名义 vCore」= TaskManager vCore 数 ÷ Slot 数
每个 Slot 的「名义 GB」 = TaskManager 内存 GB 数 ÷ Slot 数
作业总 vCore·小时 = TaskManager vCore 数 × 运行时长 × TaskManager 数量
作业总 GB·小时 = TaskManager 内存 GB 数 × 运行时长 × TaskManager 数量
我常用的估算方法:假设一个 TaskManager 有 4 个 Slot、8 GB 内存、4 vCore。那么每个 Slot 的「名义成本」就是 1 vCore + 2 GB。如果作业并行度是 8,需要 2 个 TaskManager,总成本就是 8 vCore + 16 GB 的计费量。这个估算虽然粗糙,但用来做成本对比已经够用了。
3.6 避坑指南:常见的换算误区
这些年我见过不少团队在换算上翻车,总结几个典型:
- 误区一:Slot 数 = vCore 数。这是最常见的误解。Slot 只是并发槽位,不是 CPU 核。把 Slot 数设成 vCore 数,往往导致资源争抢严重。
- 误区二:每个 Slot 独立计费。云平台按 TaskManager 整体计费,不是按 Slot。你设 2 个 Slot 和设 8 个 Slot,只要 TaskManager 规格一样,账单金额是一样的。
- 误区三:Parallelism 越大越好。Parallelism 大了,需要的 Slot 多,TaskManager 也多,成本线性增长。但吞吐量不一定线性增长——因为网络 shuffle、状态后端 IO 会成为新瓶颈。
我曾经踩过的坑:有次为了压延迟,把 Parallelism 从 8 提到了 32,TaskManager 从 2 台扩到了 8 台。结果延迟没降多少,账单翻了 4 倍。后来分析发现,瓶颈在外部存储的 IO 上,加并行度根本没用。所以我现在做成本分析,一定会先看瓶颈在哪,再决定要不要加资源。
3.7 实战:如何用换算关系做成本估算
假设你要上线一个实时特征任务,预估数据量 10 万 QPS,状态大小 500 MB。你怎么估算它的资源成本和账单?
我的做法分三步:
- 估算并行度:按每个 SubTask 处理 1-2 万 QPS 来算,10 万 QPS 需要 5-10 个并行度。取 8。
- 确定 Slot 和 TaskManager 规格:每个 TaskManager 设 4 个 Slot,需要 2 个 TaskManager。每个 TM 给 4 vCore、8 GB 内存(状态 500 MB,留余量)。
- 计算计费量:2 个 TM × 4 vCore × 24 小时 = 192 vCore·h/天。2 个 TM × 8 GB × 24 小时 = 384 GB·h/天。
按云平台单价(假设 0.1 元/vCore·h,0.01 元/GB·h),每天成本就是:192 × 0.1 + 384 × 0.01 = 19.2 + 3.84 = 23.04 元/天。
关键提醒:这个估算只是「申请资源」的成本,不是「实际使用」的成本。如果你的任务 CPU 利用率只有 20%,那 80% 的钱就白花了。后面我们会讲如何通过监控数据做「实际成本」的校准。
好了,资源粒度与计价模型的换算关系就讲到这里。记住一句话:Slot 是调度承诺,vCore·小时是账单刻度,中间的换算系数决定了你的成本效率。下一层我们会聊如何用监控数据把这些「名义成本」校准成「真实成本」。