Flink基础之Flink并行度和Slot深度剖析:资源到底怎么算
摘要
讲透 Flink 并行度与 Slot 的完整机制:并行度与 Slot 的本质区别与映射关系、算子链与 Slot Sharing 如何决定资源需求、并行度四级配置优先级,以及资源规划三步法;并给出并行度调整的五个真实踩坑点。
关键词
Flink、并行度、Parallelism、Slot、Slot Sharing、算子链、配置优先级、资源规划、数据倾斜、keyBy
很多 Flink 新手(和一部分老手)都在这两个词上栽过跟头:并行度和 Slot。调并行度时随手写个 -p 16,发现集群上任务还是排队;或者以为「并行度开得越大越快」,结果数据倾斜把吞吐拉崩。根源在于没搞清楚一个核心问题:并行度是逻辑概念,Slot 是物理概念,二者之间隔着一层「算子链 + Slot Sharing」的映射。
这一篇把它彻底讲透,最后给出一套可以照着算的资源规划方法。
一、并行度与 Slot:逻辑与物理的分工
先分清两个概念的本质:

- 并行度(Parallelism):逻辑层面的概念,指一个算子被拆成几个并行实例。
map并行度 3,就是 3 个 map 实例同时跑,每个实例处理一部分数据分区。 - Slot:物理层面的概念,TaskManager 内部划分的资源单元。
taskmanager.numberOfTaskSlots决定每个 TM 有几个 Slot,集群总 Slot 数 = Σ(各 TM 的 Slot 数)。
它们的关系是一条硬约束:作业的实际并行度 ≤ 集群可用 Slot 数。Slot 不够,任务就只能停在 SCHEDULED 状态排队。
还有个必须澄清的误区:Slot 是内存划分,不是 CPU 隔离。同一个 TM 的多个 Slot 共享同一批 CPU 核心,Slot 只约束并发任务数和内存配额。要 CPU 隔离,靠 YARN/K8s 的容器粒度,不靠 Slot。
二、任务到 Slot 的映射:算子链与槽位共享
并行实例不会一个个单独落到 Slot 上,中间有两层机制在起作用:
- 算子链(OperatorChain):并行度相同 + 数据 one-to-one 传播的算子合并成一个 Task,在同一线程内串行执行。
Source + map + filter可能只是一个 Task。 - Slot Sharing(槽位共享):默认情况下,同一作业的不同 Task(并行度匹配)可以共享同一个 Slot。
这两层叠加的效果很反直觉但非常重要:一个作业需要的 Slot 数 ≈ 作业中最大的并行度,而不是所有算子并行度之和。
比如作业 Source(并行度2) → keyBy → 聚合(并行度4) → Sink(并行度4):
- 不共享:需要 2 + 4 + 4 = 10 个 Slot;
- 默认共享:只需要 max(2,4,4) = 4 个 Slot,并行度小的链「补位」进共享 Slot。
这是 Flink 资源利用率高的核心原因,也是理解「为什么我开了 16 并行度,集群却只用了 4 个 Slot」的钥匙——要么被算子级配置覆盖了,要么共享组内并行度根本没到 16。
三、并行度的四级配置优先级
并行度可以在四个层面配置,优先级从高到低:

- 算子级(最高):
map(...).setParallelism(8),只影响单个算子,调优时最常用。 - 执行环境级:
env.setParallelism(4),作为作业内所有算子的默认值。 - 提交参数:
flink run -p 6,不改代码快速调整作业默认并行度,A/B 验证常用。 - 配置文件:
parallelism.default,全局兜底,优先级最低。
一个特殊点:Source 的并行度不完全受这套优先级控制。Kafka Source 的并行度默认取 min(分区数, parallelism),文件 Source 可以显式指定。这就是为什么有时候你设了并行度 8,Source 却只有 4 个实例——topic 只有 4 个分区。
排查技巧:Web UI 上每个算子旁都会显示实际生效的并行度,与预期不符时,按四级逐层往下查,一定是某一级配置压住了。
四、Slot Sharing 深入:资源到底怎么算
理解了默认共享,再看自定义分组和资源规划:

4.1 默认共享 vs 分组隔离
- 默认共享:所有算子属于
default组,Slot 需求 ≈ 最大并行度。省资源,但重任务聚集在同一 Slot 时会互相挤占。 - 自定义分组:
算子.slotSharingGroup("g1")把任务分组,同组共享 Slot、不同组互不干扰。比如把重聚合单独分一组,避免它和 Source 抢同一个 Slot 的线程资源。
分组是「用资源换隔离」:默认共享省资源但可能互相拖累;分组隔离保性能但多占 Slot。Slot 需求 = Σ(各组内最大并行度)。
4.2 资源规划三步法
- 确定各算子并行度:考虑数据量、状态规模、key 分布。数据量小就别开高并行度;key 数量少时并行度高只会让大部分子任务空转。
- 估算 Slot 需求:默认共享取最大并行度;有分组时按组内最大并行度求和。
- 反推 TM 数量:
TM 数 × 每 TM Slot 数 ≥ Slot 需求,并留 20% 余量应对流量波动和单 TM 故障时的任务迁移。
示例:Slot 需求 8、每 TM 4 Slot → 2 个 TM;如果要求单 TM 故障不影响作业(需 1 冗余),则要 3 个 TM——这也是生产环境常见的「多一台备着」的由来。
五、并行度调整的五个真实踩坑
- 并行度 > 总 Slot 数,作业永远起不来。YARN 上表现为作业一直 ACCEPTED/RUNNING 但不推进,Web UI 里任务全是 SCHEDULED。先看集群还剩多少 Slot,再定并行度。
- 盲开高并行度,吞吐反而下降。数据倾斜时,一个 key 的数据全压在一个子任务上,并行度再高其他实例都在空转;而且并行度翻倍,网络 shuffle 的链接数也翻倍(并行度²),序列化开销同步上涨。先解决倾斜,再谈并行度。
- keyBy 后并行度变化触发状态重分布。有状态算子的并行度调整(无论是改配置还是从 Savepoint 恢复时改动)都会触发 key group 重分布,作业恢复时有一段重算开销。无界流改并行度,必须基于 Savepoint 恢复,直接改配置重启会丢状态语义。
- 固定 key 让并行度形同虚设。
keyBy(v -> "total")把所有数据压到单并行度,其他实例空转——这是「并行度 16 但实际只有 1 个在干活」的最常见原因。key 设计要保证分布均匀。 - 忽略 Slot Sharing 直接按并行度之和申请资源。不知道默认共享机制的人,会按「所有算子并行度相加」去配 TM 数量,白白申请两三倍的资源。按最大并行度估算,能省一大半。
并行度与 Slot 的关系可以浓缩成一句话:并行度决定「逻辑上要几个实例」,Slot 决定「物理上能放几个任务」,中间由算子链和 Slot Sharing 桥接——所以资源需求 ≈ 最大并行度而非并行度之和。把「四级优先级」「默认共享省资源」「key 分布决定真实吞吐」这三件事记牢,Flink 的资源规划与并行度调优就都有了依据。
算子链和 Slot Sharing 桥接**——所以资源需求 ≈ 最大并行度而非并行度之和。把「四级优先级」「默认共享省资源」「key 分布决定真实吞吐」这三件事记牢,Flink 的资源规划与并行度调优就都有了依据。

浙公网安备 33010602011771号