大数据技术之Flink 集群架构

举报
tea_year 发表于 2025/04/30 11:35:29 2025/04/30
【摘要】 Flink集群是一个基于Apache Flink框架构建的分布式处理系统,它专为无界和有界数据流上的有状态计算而设计。Flink集群能够在各种常见的集群环境中运行,如YARN、Mesos、Kubernetes等,并具备高吞吐量、低延迟以及强大的状态管理能力。2. Flink集群的组成部分Flink集群主要由以下几个关键组件组成:‌JobManager‌:Flink集群的主节点,负责管理集群中...

Flink集群是一个基于Apache Flink框架构建的分布式处理系统,它专为无界和有界数据流上的有状态计算而设计。Flink集群能够在各种常见的集群环境中运行,如YARN、Mesos、Kubernetes等,并具备高吞吐量、低延迟以及强大的状态管理能力。

2. Flink集群的组成部分

Flink集群主要由以下几个关键组件组成:

  • JobManager‌:Flink集群的主节点,负责管理集群中的作业(Jobs)。它包含Flink ResourceManager、Flink Dispatcher和每个Flink作业的JobManager实例。JobManager负责作业的提交、调度、执行和资源管理。
  • TaskManager‌:Flink集群的工作节点,负责执行作业中的任务(Tasks)。TaskManager可以并行执行多个任务,它们之间通过高效的数据交换机制(如Netty)进行通信。
  • Client‌:客户端组件,用于提交作业到Flink集群。用户编写的Flink程序通过Client提交到JobManager,并转换成作业图(JobGraph)和执行图(ExecutionGraph)进行执行。

3. 如何搭建Flink集群

搭建Flink集群可以通过多种方式,包括本地模式、Standalone模式、YARN模式以及Docker Compose等。以下是Standalone模式的基本步骤:

  1. 下载并解压Flink安装包‌:从Apache Flink官网下载适合你系统的Flink安装包,并解压到指定目录。

  2. 配置集群环境‌:

  • 修改flink-conf.yaml文件,设置JobManager的地址、并行度等参数。
  • workers文件中列出所有TaskManager节点的IP地址或主机名。
  1. 分发Flink目录‌:将Flink目录分发到所有集群节点。

  2. 启动集群‌:在Master节点上执行start-cluster.sh脚本启动Flink集群。

  3. 验证集群状态‌:通过访问JobManager的Web UI(默认为8081端口)来验证集群是否成功启动。

4. Flink集群的工作原理

Flink集群的工作流程可以概括为以下几个步骤:

  1. 作业提交‌:用户通过Client提交Flink作业到JobManager。

  2. 作业图转换‌:JobManager将作业转换成作业图(JobGraph),并进一步优化成执行图(ExecutionGraph)。

  3. 任务调度‌:JobManager根据执行图向TaskManager申请资源并调度任务执行。

  4. 任务执行‌:TaskManager执行分配给自己的任务,并与其他TaskManager进行高效的数据交换。

  5. 状态管理‌:Flink提供了强大的状态管理机制,确保任务在发生故障时能够从最近的状态恢复并继续执行。

核心组件

按照上面的介绍,Flink 核心架构的第二层是 Runtime 层, 该层采用标准的 Master - Slave 结构, 其中,Master 部分又包含了三个核心组件:Dispatcher、ResourceManager 和 JobManager,而 Slave 则主要是 TaskManager 进程。它们的功能分别如下:

  • JobManagers (也称为 masters) :JobManagers 接收由 Dispatcher 传递过来的执行程序,该执行程序包含了作业图 (JobGraph),逻辑数据流图 (logical dataflow graph) 及其所有的 classes 文件以及第三方类库 (libraries) 等等 。紧接着 JobManagers 会将 JobGraph 转换为执行图 (ExecutionGraph),然后向 ResourceManager 申请资源来执行该任务,一旦申请到资源,就将执行图分发给对应的 TaskManagers 。因此每个作业 (Job) 至少有一个 JobManager;高可用部署下可以有多个 JobManagers,其中一个作为 leader,其余的则处于 standby 状态。

  • TaskManagers (也称为 workers) : TaskManagers 负责实际的子任务 (subtasks) 的执行,每个 TaskManagers 都拥有一定数量的 slots。Slot 是一组固定大小的资源的合集 (如计算能力,存储空间)。TaskManagers 启动后,会将其所拥有的 slots 注册到 ResourceManager 上,由 ResourceManager 进行统一管理。

  • Dispatcher:负责接收客户端提交的执行程序,并传递给 JobManager 。除此之外,它还提供了一个 WEB UI 界面,用于监控作业的执行情况。

  • ResourceManager :负责管理 slots 并协调集群资源。ResourceManager 接收来自 JobManager 的资源请求,并将存在空闲 slots 的 TaskManagers 分配给 JobManager 执行任务。Flink 基于不同的部署平台,如 YARN , Mesos,K8s 等提供了不同的资源管理器,当 TaskManagers 没有足够的 slots 来执行任务时,它会向第三方平台发起会话来请求额外的资源。

flink-application-submission.png


Task & SubTask

上面我们提到:TaskManagers 实际执行的是 SubTask,而不是 Task,这里解释一下两者的区别:

在执行分布式计算时,Flink 将可以链接的操作 (operators) 链接到一起,这就是 Task。之所以这样做, 是为了减少线程间切换和缓冲而导致的开销,在降低延迟的同时可以提高整体的吞吐量。 但不是所有的 operator 都可以被链接,如下 keyBy 等操作会导致网络 shuffle 和重分区,因此其就不能被链接,只能被单独作为一个 Task。 简单来说,一个 Task 就是一个可以链接的最小的操作链 (Operator Chains) 。如下图,source 和 map 算子被链接到一块,因此整个作业就只有三个 Task:

flink-task-subtask.png


解释完 Task ,我们在解释一下什么是 SubTask,其准确的翻译是: A subtask is one parallel slice of a task,即一个 Task 可以按照其并行度拆分为多个 SubTask。如上图,source & map 具有两个并行度,KeyBy 具有两个并行度,Sink 具有一个并行度,因此整个虽然只有 3 个 Task,但是却有 5 个 SubTask。Jobmanager 负责定义和拆分这些 SubTask,并将其交给 Taskmanagers 来执行,每个 SubTask 都是一个单独的线程。

资源管理

理解了 SubTasks ,我们再来看看其与 Slots 的对应情况。一种可能的分配情况如下:

flink-tasks-slots.png


这时每个 SubTask 线程运行在一个独立的 TaskSlot, 它们共享所属的 TaskManager 进程的TCP 连接(通过多路复用技术)和心跳信息 (heartbeat messages),从而可以降低整体的性能开销。此时看似是最好的情况,但是每个操作需要的资源都是不尽相同的,这里假设该作业 keyBy 操作所需资源的数量比 Sink 多很多 ,那么此时 Sink 所在 Slot 的资源就没有得到有效的利用。

基于这个原因,Flink 允许多个 subtasks 共享 slots,即使它们是不同 tasks 的 subtasks,但只要它们来自同一个 Job 就可以。假设上面 souce & map 和 keyBy 的并行度调整为 6,而 Slot 的数量不变,此时情况如下:

flink-subtask-slots.png


可以看到一个 Task Slot 中运行了多个 SubTask 子任务,此时每个子任务仍然在一个独立的线程中执行,只不过共享一组 Sot 资源而已。那么 Flink 到底如何确定一个 Job 至少需要多少个 Slot 呢?Flink 对于这个问题的处理很简单,默认情况一个 Job 所需要的 Slot 的数量就等于其 Operation 操作的最高并行度。如下, A,B,D 操作的并行度为 4,而 C,E 操作的并行度为 2,那么此时整个 Job 就需要至少四个 Slots 来完成。通过这个机制,Flink 就可以不必去关心一个 Job 到底会被拆分为多少个 Tasks 和 SubTasks。

flink-task-parallelism.png


组件通讯

Flink 的所有组件都基于 Actor System 来进行通讯。Actor system是多种角色的 actor 的容器,它提供调度,配置,日志记录等多种服务,并包含一个可以启动所有 actor 的线程池,如果 actor 是本地的,则消息通过共享内存进行共享,但如果 actor 是远程的,则通过 RPC 的调用来传递消息。

flink-process.png


程序与数据流(DataFlow)

image-20201123153132346.png


所有的Flink程序都是由三部分组成的: Source 、Transformation和Sink。 Source负责读取数据源,Transformation利用各种算子进行处理加工,Sink负责输出。 在运行时,Flink上运行的程序会被映射成“逻辑数据流”(dataflows),它包含了这三部分。每一个dataflow以一个或多个sources开始以一个或多个sinks结束。dataflow类似于任意的有向无环图(DAG)。在大部分情况下,程序中的转换运算(transformations)跟dataflow中的算子(operator)是一一对应的关系,但有时候,一个transformation可能对应多个operator。

执行图(ExecutionGraph)

由Flink程序直接映射成的数据流图是StreamGraph,也被称为逻辑流图,因为它们表示的是计算逻辑的高级视图。为了执行一个流处理程序,Flink需要将逻辑流图转换为物理数据流图(也叫执行图),详细说明程序的执行方式。

Flink 中的执行图可以分成四层:StreamGraph -> JobGraph -> ExecutionGraph -> 物理执行图。 StreamGraph:是根据用户通过 Stream API 编写的代码生成的最初的图。用来表示程序的拓扑结构。 JobGraph:StreamGraph经过优化后生成了 JobGraph,提交给 JobManager 的数据结构。主要的优化为,将多个符合条件的节点 chain 在一起作为一个节点,这样可以减少数据在节点之间流动所需要的序列化/反序列化/传输消耗。 ExecutionGraph:JobManager 根据 JobGraph 生成ExecutionGraph。ExecutionGraph是JobGraph的并行化版本,是调度层最核心的数据结构。 物理执行图:JobManager 根据 ExecutionGraph 对 Job 进行调度后,在各个TaskManager 上部署 Task 后形成的“图”,并不是一个具体的数据结构。

4.7 并行度(Parallelism)

Flink程序的执行具有并行、分布式的特性。 在执行过程中,一个流(stream)包含一个或多个分区(stream partition),而每一个算子(operator)可以包含一个或多个子任务(operator subtask),这些子任务在不同的线程、不同的物理机或不同的容器中彼此互不依赖地执行。 一个特定算子的子任务(subtask)的个数被称之为其并行度(parallelism)。一般情况下,一个流程序的并行度,可以认为就是其所有算子中最大的并行度。一个程序中,不同的算子可能具有不同的并行度。

image-20201123153403057.png

Stream在算子之间传输数据的形式可以是one-to-one(forwarding)的模式也可以是redistributing的模式,具体是哪一种形式,取决于算子的种类。 One-to-one:stream(比如在source和map operator之间)维护着分区以及元素的顺序。那意味着map 算子的子任务看到的元素的个数以及顺序跟source 算子的子任务生产的元素的个数、顺序相同,map、fliter、flatMap等算子都是one-to-one的对应关系。 类似于spark中的窄依赖 Redistributing:stream(map()跟keyBy/window之间或者keyBy/window跟sink之间)的分区会发生改变。每一个算子的子任务依据所选择的transformation发送数据到不同的目标任务。例如,keyBy() 基于hashCode重分区、broadcast和rebalance会随机重新分区,这些算子都会引起redistribute过程,而redistribute过程就类似于Spark中的shuffle过程。 类似于spark中的宽依赖

任务链(Operator Chains)

相同并行度的one to one操作,Flink这样相连的算子链接在一起形成一个task,原来的算子成为里面的一部分。将算子链接成task是非常有效的优化:它能减少线程之间的切换和基于缓存区的数据交换,在减少时延的同时提升吞吐量。链接的行为可以在编程API中进行指定。

image-20201123153534865.png

总结

最后基于上面的介绍,来总结一下 Flink 的优点:

  • Flink 是基于事件驱动 (Event-driven) 的应用,能够同时支持流处理和批处理;

  • 基于内存的计算,能够保证高吞吐和低延迟,具有优越的性能表现;

  • 支持精确一次 (Exactly-once) 语意,能够完美地保证一致性和正确性;

  • 分层 API ,能够满足各个层次的开发需求;

  • 支持高可用配置,支持保存点机制,能够提供安全性和稳定性上的保证;

  • 多样化的部署方式,支持本地,远端,云端等多种部署方案;

  • 具有横向扩展架构,能够按照用户的需求进行动态扩容;

  • 活跃度极高的社区和完善的生态圈的支持。

【声明】本内容来自华为云开发者社区博主,不代表华为云及华为云开发者社区的观点和立场。转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息,否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。