Flink 为什么使用的slot数量比task少? task subtask slot 是什么样的关系呢?
前言
最近在部署flink集群,遇到了一些问题,觉得是蛮有意思的事情,所有就写点材料,和有需要的朋友交流分享一下。本来我只是为了解决问题,现在既然写点材料的话为了专业性,所以我特地去官网查看了部分词汇,有需要的兄弟直接链接送上。词汇表
TaskManager 和 JobManager
flink集群有jobmanager和flinkmanager
- jobManager 是 Flink 集群的主节点。
jobmanager用于分配任务,自己不执行任务,一般只有一个。高可用可能有多个 ,其中一个始终是 leader,其他的则是 standby - taskManager 是 Flink 集群 的工作进程
taskmanager有多个,用于执行任务。
领导一般只有一个,只管天马行空想需求,下面开发团队有一堆,熬夜实现领导的天马行空。
Task Slots
- Task Slots 每个 TaskManager都是一个 JVM 进程,可以在单独的线程中执行一个或多个 subtask。为了控制一个 TaskManager 中接受多少个 task,就有了所谓的 task slots。
一个taskmanager可以配置多个slot,平分资源。也就是一个团队可以招多个人,但是总共就那么多钱。不过还是不太一样,毕竟你旁边的同事可能工资比你高事情比你少。在这里可能事情也是不一样多,但工资还是一样的,比较公平。
Task 和 subtask
-
task 是工作的基本单元
下图就表示有6个task
-
subTask task 的每一个分区会形成一个 subTask
其实有多少个并行度就会有多少个分区,如上图看到的每个并行度都是40,我随意点开一个可以看到有40个subtask
如何计算有task和subtask数量
以wordcount为例
//源
DataStream<String> inputDataStream = env.addSource(...).setParallelism(2);//并行度2
//转换
DataStream<Event> flatStream = inputDataStream.flatMap(...).setParallelism(2);//并行度2
//分组 开窗 聚合
DataStream<statistic> resultStream = flatStream.keyBy ("id").timeWindow (..).apply(..).setParallelism(2);//并行度2
//输出
resultStream.addSink(...).setParallelism(1);//并行度1
网上找了个DAG图,代码根据图改的。
图中 source/map 的并行度都是 2,keyby/window/apply 的并行度也都是 2,sink 的是 1
FIink 算子连接模式
补充一下上FIink 算子连接模式的概念,上下游算子通过数据流进行连接,有两种模式。
-
One-to-one :保留元素的分区和排序。这意味上下游运算符将获取到相同顺序元素。
需要满足没有洗牌,且并行度一样。不满足其中一项就不属于One-to-one -
Redistributing :更改流的分区。每个运算符都将数据发送到不同的目标子任务,具体取决于所选的转换。比如 keyBy()(其重新分区通过散列键),broadcast(), or rebalance()(其重新分区随机地)。在重新分配交换中,元素之间的顺序仅保留在每对发送和接收子任务中。
因此 source 到 map 属于 One-to-one 的模式,所有 source 和 map 划分成一个 task,后面的 map 到 keyBy ,和最后的 sink 都有 洗牌 产生,并行度发生改变,所以 keyBy,sink 都是一个单独的 task。
因此共有 3 个task,其中 source,map 并行度是 2,所以有两个 subTask,以此类推共有 5 个 subtask
Operator Chains
算子链由两个或多个连续的 Operator 组成,两者之间没有任何的洗牌。同一算子链内的算子可以彼此直接传递 record,而无需通过序列化或 Flink 的网络栈。它减少线程间切换、缓冲的开销,并且减少延迟的同时增加整体吞吐量,链行为是可以配置的;
经典的 WordCount 为例,下面这幅图,展示了 Source 并行度为 1,FlatMap、KeyAggregation、Sink并行度均为 2,最终以 5 个并行的线程来执行的优化过程
上图中将 KeyAggregation 和 Sink 两个 operator 进行了合并,因为这两个合并后并不会改变整体的拓扑结构。
注意 正是因为这样的优化,一个slot就有可能包含多个task。就出现了我遇到的情况,40个task只用10个槽。
SlotSharingGroup
有时了防止同一个 slot 包含太多的 task,或者我们希望把计算逻辑复杂的算子单独使用 slot ,提高计算速度,Flink 提供了资源组的概念。group 就是对 算子 进行分组,同一 组 的不同 算子 task 可以共享同一个 slot。
默认所有 operator 属于同一个组"default",可以通过 slotSharingGroup() 为不同的 operator 设置不同的group。
.slotSharingGroup(SINK_GROUP_NAME);