Flink工作原理
Flink作为新的stream计算引擎,这两年社区的活跃度很高。对于Flink 既可以处理stream data也可以处理batch data,同时可以兼顾Spark以及Sparkstreaming的功能,与Spark不同的是,Flink本质上只有stream的概念,batch被认为是special stream。Flink主要有以下几个角色需要大家了解,对于Flink的开发是很有帮助的。也便于自己后期翻阅。
JobClient:
负责接收程序,解析和优化程序的执行计划,然后提交执行计划到JobManager。这里执行的程序优化是将相邻的Operator融合,形成OperatorChain,Operator的融合可以减少task的数量,提高TaskManager的资源利用率。
JobManagers:
负责申请资源,协调以及控制整个job的执行过程,具体包括,调度任务、处理checkpoint、容错等等
TaskManager:
TaskManager运行在不同节点上的JVM进程(process),负责接收并执行JobManager发送的task,并且与JobManager通信,反馈任务状态信息,如果说JobManager是master的话,那么TaskManager就是worker用于执行任务。每个TaskManager像是一个容器
,包含一个或者多个Slot。
Slot:
Slot是TaskManager资源粒度的划分,每个Slot都有自己独立的内存。所有Slot平均分配TaskManager的内存,值得注意的是,Slot仅划分内存,不涉及cpu的划分。每个Slot可以运行多个task。Slot的个数就代表了一个程序的最高并行度。
Task:
Task是在operators的subtask进行链化之后形成的,具体Flink job中有多少task和operator的并行度和链化的策略有关,为了方便大家理解,可以参考图5中所示的理解。
SubTask:
因为Flink是分布式部署的,程序中的每个算子,在实际执行中被分隔为一个或者多个subtask,运算符子任务(subtask)的数量是该特定运算符的并行度。数据流在算子之间流动,就对应到SubTask之间的数据传输。Flink允许同一个job中来自不同task的subtask可以共享同一个slot。每个slot可以执行一个并行的pipeline。可以将pipeline看作是多个subtask的组成的。
Parallel Dataflows
Flink程序本质上是并行和分布式的。在程序执行期间,一个流会生成一个或者多个stream partition,并且一个operator会生成一个或者多个operator subtask。operator的 subtask 彼此之间是独立的,分别在不同的线程里去执行并且可能分布在不同的机器上或者containers上。
operator的subtasks的数量等于该操作算子的并行度的数量。流的并行度有总是取决于产生它的操作算子的并行度决定的。同一个flink程序中的不同的operators可能有不同的并行度。
数据流在两个operators之间进行传递的方式有两种:one-to-one 模式 和 redistributing 模式
①:one-to-one 模式:两个operator用此模式传递的时候,会保持数据的分区数和数据的排序,比如:在下图中Source和map() operators之间的数据传递方式;
②:Redistributing 模式:这种模式会改变数据的分区数;每个一个operator subtask会根据选择transformation把数据发送到不同的目标subtasks,比如keyBy()会通过hashcode重新分区,broadcast()和rebalance()方法会随机重新分区,比如:在下图中map()和keyBy/window ,keyBy/window和Sink之间的数据传递方式;
Task and Operator Chains
对于分布式计算,Flink将operator 的subtasks链化在一起形成tasks。每个task在一个线程中被执行。将operators链化在一起形成tasks是比较好的一个优化:他减少了线程和线程之间的切换和缓冲的开销,增加了吞吐量降低了延迟。对于operator的链化行为,可以根据个人来去调整。详情参考官网
下图中operators经过链化之后,仅仅需要5个并行的线程。
Task Slots and Resources
①每一个worker(TaskManager) 都是一个JVM进程,他可能会在独立的线程中执行一个或者多个subtask。为了控制worker能够接收多个task。worker通过task slot来进行控制(一个worker至少有一个task slot)。
②每个task slot表示TaskManager拥有资源的一个固定大小的子集。假如一个TaskManager有三个slot,那么它会将其管理的内存分成三份给各个slot。slot的资源化意味着一个job的subtask将不需要跟来自其它job的subtask竞争被管理的内存。
③通过调整task slots的数量,用户可以定义subtasks它们之间如何互相隔离。如果一个TaskManager一个slot,那将意味着每个task group独立的运行在JVM中。而一个TaskManager多个slot意味着更多的subtask可以共享一个JVM。而在同一个JVM进程中的task将共享TCP连接和心跳消息。它们也可能共享数据集和数据结构,这样可以减少每个task的负载。
默认,如果subtask是来自相同的job,但不是相同的task,Flink允许subtask共享slot。这样就会出现一个slot可能容纳一个job中的整个pipeline。允许slot共享有以下两个好处:
① Flink集群需要的task slots的数量和作业中的最高并行度的一致。不需要计算一个程序总共包含多少个task。
②更好的利用资源。如果没有slot共享,非密集型source/map()子任务将阻塞与资源密集型窗口子任务一样多的资源;在slot共享的话,将我们图6的示例中的基本并行度从2提高到6,可以充分利用slot资源,同时确保繁重的subtasks在Taskmanager中公平分配。