深入浅出:Flink运行时架构、核心组件与任务提交全解析

发布时间:2026/10/17 9:43:16
深入浅出:Flink运行时架构、核心组件与任务提交全解析 在开始聊 Flink 运行时架构之前我想先还原一个特别真实的场景你刚写完一个 Flink 作业满怀信心地点下运行按钮结果集群上除了日志之外你并不知道代码到底被谁接收了、拆成了什么、又怎么分配到机器上跑的。反正它跑起来了数据也出结果了但一旦遇到性能问题、反压告警、或者我的任务为什么卡在 RUNNING 状态这种灵魂拷问马上就会发现自己对运行时的理解是个黑洞。这种能跑但不懂的状态恰恰是学习 Flink 最需要打破的。因为 Flink 的运行时架构是所有作业调度的地基也是排查问题、做性能调优时唯一能依赖的地图。这篇文章我用最白话的方式把运行时Runtime架构的整体组成、各个组件之间的真实分工、以及一条指令从提交到执行完毕的完整旅程讲透。不是那种上来就给你甩图然后逐字念概念的笔记而是先把为什么要有这些组件说清楚再带你走一遍流程最后把我自己调试时踩过的坑一并交代。这篇内容定位是基础理论的第一篇但并不会停留在概念表面。读完之后你应该能对着监控页面里的每个作业说清楚到底谁在负责哪件事也可以口头向别人解释一个 Flink 任务在集群中是如何被组织起来的。1. 在你点下运行按钮之前Flink 运行时到底在解决什么问题1.1 运行时架构不是设计图而是运行真相很多初学者把 Flink 运行时架构当成一张静态的拓扑图来记记完了还是不知道它存在的必要性。我这里换个角度先思考一个问题当你的 Java 代码里出现了env.execute()这行代码背后的真正含义是什么它不是开始执行而是把我的计算逻辑提交出去交给一个分布式运行时环境去编排。这个分布式运行时环境就是 Flink 的 Runtime 层。它要解决的核心问题非常朴素一个单机上跑不动的数据任务怎么拆分到多台机器上协作完成机器之间的数据怎么传递某个机器挂了怎么办任务执行到一半另一个任务来了资源怎么分配这些问题每一个都很现实跟代码能否编译通过完全不相关但跟生产环境能不能稳定运行直接相关。这也是为什么运行时的理解深度直接决定你排查生产问题的效率。1.2 从单个程序到分布式协作整个架构围绕的核心理念Flink 运行时架构设计的核心理念我概括成一个词分工与协作。分工体现在角色的分离上谁负责接收任务、谁负责管理资源、谁负责执行计算全部拆开协作体现在这些角色必须通过消息传递、心跳上报、状态同步来协同工作形成一个自洽的闭环。打个比方这就像一家餐厅的后厨有人负责接单接收作业有人负责买菜和备菜管理资源有人负责掌勺和装盘执行计算还有人盯着整个流程保证出餐节奏协调调度。每个角色看起来独立但后厨能正常运转靠的是各岗位之间的高效协作。Flink 的运行时就是这套后厨系统。你不理解它就相当于在后厨干活却不知道谁管调拨食材、谁管菜肴出锅出了问题也只能干着急。2. 整体架构的角色划分为什么它长得像一套微型操作系统2.1 Master-Slave 式协作一个控制器带一帮执行者Flink 运行时整体架构采用了经典的 Master-Slave 协作模式。Master 方向的核心是 JobManager负责整个作业的控制与调度Slave 方向的核心是 TaskManager负责真正执行数据计算任务。这两层之分可以说是 Flink 架构的骨架。多提一层这种控制与执行分离的思想在分布式系统中并不罕见。Spark 也有 Driver 与 Executor 之分MapReduce 也有 JobTracker 与 TaskTracker 的概念。为什么大家都采用这种方式因为控制面和数据面承担的任务性质完全不同控制面需要频繁做决策、通信、维护状态对延时敏感数据面则需要大量 CPU、内存和网络带宽来搬运和处理数据。两者混在一起必然互相干扰要么控制决策变慢要么数据吞吐被拖垮。所以你在理解 Flink 架构时先别把注意力放在组件的名字上而是要意识到它首先是一个控制系统 执行系统的组合体。后续所有组件的职责都可以归类到这两条线上。2.2 协调者、资源管理、执行节点组件之间的基本协作逻辑在宏观的 Master-Slave 骨架之下Flink 进一步细分了组件职责主要包括四类JobManager、ResourceManager、TaskManager、Dispatcher。JobManager 是作业控制大脑负责作业的调度、检查点协调、故障恢复ResourceManager 是资源调度台负责集群资源的分配与回收TaskManager 是计算执行单元负责真正运行任务并管理本地的内存、网络缓冲Dispatcher 是作业接待前台负责接受作业提交、拉起 JobManager。这四类角色协作的基本链路是这样的客户端向 Dispatcher 提交作业Dispatcher 通知 ResourceManager 申请资源ResourceManager 把可用任务槽分给 JobManagerJobManager 将作业图转化为执行图并给 TaskManager 分配具体任务TaskManager 启动线程执行任务期间持续向 JobManager 上报心跳与状态。这套链路我后面会结合提交流程详细展开。现在你只需要记住每个组件都只负责一件事但每件事都是整条链路上不可缺的一环。理解组件的方式不是死记功能列表而是把这些功能串成一个闭环。3. 核心组件逐个拆解JobManager、ResourceManager、TaskManager、Dispatcher 的真实分工3.1 JobManager不处理数据却决定一切先给 JobManager 一个精准定位它不处理任何数据但作业的一切行为都在它的管辖范围内。你可以把 JobManager 想象成一场演出的导演——演员TaskManager在台上表演但剧本分镜、出场顺序、遇上突发状况如何调整都由导演控制。JobManager 的职责主要可以拆成四块。第一块作业图调度。用户代码在客户端被翻译成 JobGraphJobManager 接收后会把它进一步解析为 ExecutionGraph也就是真正可调度执行的并行版本再根据可分配的任务槽情况把具体任务交给不同的 TaskManager 去执行。这个过程直接决定每个算子在哪里运行、并行度如何分布。第二块检查点协调。Flink 的容错机制整体以检查点为基础而每个检查点的发起、完成确认、失败处理都由 JobManager 发起协调。它会向 Source 算子注入 barrier让 barrier 在数据流里流动各算子感受到 barrier 之后记录状态最后再由 JobManager 确认整个检查点是否成功。第三块故障恢复。当 TaskManager 崩溃或任务执行失败时JobManager 负责重新调度受影响的任务并从最近一次成功的检查点恢复状态。这里值得一提的是恢复方式由重启策略配置但谁来决定恢复、如何恢复的钥匙始终在 JobManager 手里。第四块任务生命周期的管理。任务提交、取消、停止这些操作最终都由 JobManager 落地。它需要实时掌握每个任务的状态从 CREATED、RUNNING、FINISHED 到 FAILED每个状态转换都有严格的语义。说到这里顺带讲一个很多人误解的关键点JobManager 在典型的高可用部署中并不是单点。生产中通常配置为 Active-Standby 模式多个 JobManager 实例共享 ZooKeeper 之类的高可用服务来选举保证主节点挂了之后 standby 能立刻接管。3.2 ResourceManager集群资源的调度台ResourceManager 这个名字很容易让人误以为它管理的是 CPU 和内存这类物理资源其实不是。在 Flink 的模型里资源的基本单位是任务槽SlotResourceManager 管理的就是这些 Slot。那 Slot 究竟是什么可以把 TaskManager 的内存资源按个数切分为若干个槽位每个槽位能运行一个任务。这里容易踩的坑一个 Slot 能运行的未必只是一个并行子任务如果算子链开启了多个算子可以共享一个 Slot但同一 Slot 内不会同时运行两个不同任务的子任务。ResourceManager 做的事情就是维护每个 TaskManager 上 Slot 的分配状态。具体场景也很有意思。当作业提交之后JobManager 会向 ResourceManager 请求需要多少个 Slot如果当前集群空闲 Slot 足够ResourceManager 直接分配如果不够它会根据配置向外部资源平台比如某个资源调度系统、容器平台或 Kubernetes发起申请再启动新的 TaskManager 来扩容。任务结束后多余的 Slot 会被回收实现资源的弹性伸缩。所以当你看到集群上某个作业结束后资源仍然卡了一段时间往往跟 Slot 释放的延迟策略有关系这也是我在第 5 节会单独说明的坑。3.3 TaskManager真正搬数据干活的工人TaskManager 是最接地气的组件因为它是实际执行计算的地方。你的 map、flatMap、window 操作最终都以任务形式跑在 TaskManager 的 Slot 里。TaskManager 的核心职责包括三块一是接收 JobManager 分配的任务并执行二是负责数据在网络层面的交换包括序列化、反序列化、网络缓冲区的管理三是维护任务运行需要的本地状态比如迭代计算中的状态存储或流式算子状态。这里要补充一个很容易混淆的知识点同一种算子逻辑的多个并行实例会被拆分成多个 sub-task每个 sub-task 绑定一个 Slot。如果并行度是 4那么图上画的一个算子在运行时会变成 4 个并行的执行单元。数据流从一个算子流向另一个算子时实际上存在大量跨网络的数据传递这时候 TaskManager 的本地缓冲机制与网络通信配置就显得特别关键了。实际调优时很多人频繁调整并行度却忘了 Slot 数量约束。一个 TaskManager 能承载的并行任务数等于它的 Slot 数量由taskmanager.numberOfTaskSlots配置。如果你把并行度调成 10但整个集群只有三个 TaskManager 各两个 Slot实际可用并行度就是 6多余的任务只能排队等待作业时间直接拉长。3.4 Dispatcher 与 Web UI经常被忽视的入口环节Dispatcher 在运行时架构里容易被一笔带过因为它不参与核心计算只负责作业的接收与创建的协调。但在实际部署中Dispatcher 的作用至关重要。你通过命令行提交作业时实际第一个打交道的就是 Dispatcher。它接收作业之后将作业交给 JobManager并负责启动一个新的 JobManager 实例在应用模式下。它也承载了 Web 界面的访问入口无论是上传作业包、查看日志、还是触发 savepoint很多管理操作都要经由 Dispatcher 提供的 HTTP 服务。这也解释了为什么在 Session 模式下无论提交了多少个作业集群里都只有一个 Dispatcher 在跑而在应用模式下每个作业都会创建自己的 Dispatcher 和 JobManager隔离性更强。这两者的取舍我会在下一节重点讲。4. 任务提交流程全景三种模式下的代码级解释4.1 三种部署模式的差别不只是命名方式不同在掌握组件职责之后我们可以来看一条真实的任务提交链路。但在讲链路前必须先把三种模式区分清楚因为很多人在这一步就开始犯迷糊了。Flink 提供了三种推荐的使用模式Session Mode会话模式、Per-Job Mode每作业模式、Application Mode应用模式。Session Mode先启动一个常驻集群包含 Dispatcher 和 ResourceManager之后提交的多个作业共享这套常驻组件每个作业启动专门的 JobManager 和 TaskManager。优点是启动快、资源复用高缺点是隔离性差一个作业的异常可能影响同集群的其他作业。Per-Job Mode在部分资源平台存在差异这里说的是经典客户端提交模式每个作业提交时会启动一套完整的 Flink 集群作业结束就释放隔离性极佳。但它的启动成本高因为每次都要从零拉起集群组件。Application Mode是三种模式里最推荐的。它不是按作业粒度而是按应用粒度启动同一个应用中包含的多个作业共享一套运行时环境main()方法在集群上执行从而规避了客户端作为单点的问题。这对长任务和封装性要求高的场景非常友好。三者的区别我再用一个日常类比解释Session 模式像一个开放工位区谁来了都能坐灵活但干扰大Per-Job 模式像每次开会都租一间独立会议室私密但费时费力Application 模式则像给一个项目组租一套固定办公区人员可以内部流动整体固定。4.2 Standalone 场景下一次任务提交的完整链路为了让大家彻底看清组件协作过程我以 Standalone 集群 Session 模式为例把一条命令从敲下到任务跑起来的全过程拆开讲。假设你执行了这样的命令flink run -d -p 2 -c com.example.MyFlinkJob /path/to/myjob.jar第一步客户端向 Dispatcher 发送提交请求这个请求里包含打包好的 JobGraph、用户代码目录以及执行配置。如果集群启用 Web 服务Dispatcher 还会同时处理 HTTP 请求。第二步Dispatcher 收到请求后会先启动一个 JobManager 实例Session 模式下若已有 JobManager则直接复用并把 JobGraph 交给它。第三步JobManager 开始解析 JobGraph将其转为 ExecutionGraph。这个过程看似微小但很重要它会做算子链合并优化决定哪些算子可以串在一个任务里执行直接影响最终的任务数量。第四步JobManager 根据 ExecutionGraph 需要的 Slot 数量向 ResourceManager 发起资源请求。第五步ResourceManager 检查集群中 TaskManager 的空闲 Slot。如果足够它直接分配 Slot并告知 JobManager 具体是哪些 TaskManager 上的哪些 Slot如果不足它会与 TaskManager 通信要求启动新的 TaskManager 来补充资源。第六步JobManager 将任务部署到分配好的 Slot 上TaskManager 开始真正执行任务。任务之间的数据流转自动建立整个作业进入 RUNNING 状态。第七步任务运行过程中TaskManager 持续向 JobManager 发送心跳JobManager 也会主动推进检查点、监控任务状态。这里有个细节值得思考客户端提交完就退出了作业还能继续跑吗答案是可以。JobGraph 已经完整提交到集群侧JobManager 本身管理与调度它客户端不再承担后续责任。所以即使提交命令的终端断了作业也能继续运行。这个特性对远程提交极其重要很多人踩过终端关了任务被杀了的坑其实根源在于客户端与集群的交互方式或部署模式选错了。4.3 一条命令背后的链路追踪如何验证你的理解如果你读完上面链路仍然觉得抽象我建议用一个非常实用的验证方法直接去看日志和 Web UI。第一步在 Standalone 集群启动后提交一个最简单的测试任务注意观察控制台输出和 Web UI 上的 Task Managers 数量变化。第二步将任务取消或等待完成再看看 Slot 释放过程。你会发现 TaskManager 在空闲一段时间后或按照配置被回收这个过程可以让你对 ResourceManager 的调度逻辑有直观体感。第三步查看 JobManager 日志中与 Checkpoint 相关的记录找到 Completed checkpoint 和 barrier 相关的关键词理解 JobManager 与 TaskManager 在容错机制中的协作。这种做法比单纯读图管用得多因为你会亲眼看到组件之间发生的消息交换而这才是运行时架构的真实面貌。5. 从明白了到不再踩坑运行时架构的常见误区与判断方法5.1 误区一Slot 数量等于并行度这是我见过最多人搞混的概念。Slot 是 TaskManager 的一种资源单元并行度是算子的逻辑并行实例数。两者之间的真实关系是一个 Slot 可以执行串行合并后的多个算子子任务但同一时刻只能执行一个并行子任务。举例来说假设一个作业有三个算子source、flatMap、sink每个的并行度都是 2。如果这三个算子没有开启算子链被拆开那总共就是 6 个子任务如果有两个算子被链在一起则子任务数量减少。分配的 Slot 足够放这些子任务就行并不要求 Slot 数量等于并行度。实际操作中判断资源是否够用的正确方式是看子任务总量与Slot 总量而不是简单比较并行度。这也是为什么 TaskManager 的 Slot 数不宜设太小或太大太小会造成过度的任务排队太大会让单个 TaskManager 负担过重反而拖慢数据交换速度。5.2 误区二内存都是 TaskManager 在管理JobManager 不重要JobManager 虽然不处理数据但它本身也要消耗内存。尤其在作业规模大、检查点频繁时JobManager 需要维护的作业状态、元数据、协调信息量会明显上升。如果你在生产环境把 JobManager 的内存配置得很小就可能出现作业频繁无法调度、状态不一致、恢复失败的现象。这也是为什么官方建议 JobManager 的 JVM 堆内存要根据作业并行度、状态规模来预留而不是随意填个默认值。实际项目里我曾经遇到一个作业在吞吐量波动时反复重启最后查下来不是代码问题而是 JobManager 内存不足导致检查点协调超时。可以做一个简单自检当你的 Flink 作业出现类似 Checkpoint expired before completing 这类报错时不要只盯着 TaskManager 的堆内存先确认 JobManager 侧的内存与 GC 情况。5.3 我的调试习惯先看作业图再看资源最后看日志跑过不少生产环境的任务之后我养成了相对固定的排查顺序也想在这里分享给大家。第一步先看 Web UI 上的作业图确认最终生成了多少个 ExecutionVertex、算子链怎么合并的。这一步能告诉你代码逻辑在运行时被拆成了什么样子能快速定位为什么我的算子并行度好像没生效这类诡异问题。第二步核对集群资源重点看每个 TaskManager 的 Slot 使用率和空闲 Slot 分布。如果任务阻塞在 Waiting for resources 或 Deploying 状态那很大概率是资源不够或 TaskManager 异常。第三步才去看日志。我一般先看 JobManager 日志再看 TaskManager 日志最后根据报错关键字定位具体任务。养成从控制面到数据面的排查顺序比上来就在 TaskManager 日志里大海捞针高效得多。结语部分分享一个我自己的体会Flink 运行时架构这个概念入门时容易觉得抽象、离我太远但真正进入调度链路和排查现场之后你会发现自己对分布式计算的理解会有一个跃升。因为你在学习运行时的时候其实是在学习分布式系统最核心的协作机制——控制面如何做决策数据面如何执行两者如何通过心跳和消息维持一致性。这套机制在很多其他分布式框架里也一样通用。如果你刚学完这篇文章我强烈建议你不要停留在看懂而是找一个测试集群实际提交一个任务把作业图、Slot 分配情况、JobManager 和 TaskManager 的日志分别打开对照这篇文章的组件职责去观察。查一次生产问题胜过读十遍原理。下一篇我再展开讲运行时架构里的关键机制比如算子如何被拆分成任务、任务之间的数据交换策略、以及状态和检查点是如何在组件之间协作完成的。有兴趣的可以先关注别在基础阶段给自己留下盲区。

关于本文作者

来自尧图内容编辑团队

尧图内容编辑团队 内容团队

尧图内容编辑团队

本文由尧图网络内容编辑团队执笔。团队由资深项目经理、前端工程师与设计师组成,所有内容均来自亲手交付的真实项目,先讲清问题、再给出可落地的解法。尧图深耕北京网站建设十年,服务过京华建材集团、智造科技等各行业客户,把一线经验沉淀为可复用的行业观察。

  • 十年建站经验,覆盖建材、制造、服务、文创等
  • 项目经理把关选题与事实准确性
  • 工程师与设计师联合撰写专业细节
  • 统一编辑规范,保证文风与排版一致
  • 每月复盘转化数据,迭代选题方向

延伸阅读

相关资讯与近期热门内容

深度阅读推荐

建站决策前值得细读的三篇

网站改版的5个关键决策
2024-08-12

网站改版的5个关键决策

什么时候该改版、改到什么程度、如何避免流量掉光,京华建材集团改版复盘给出答案。

获取专属建站方案

看完文章,把您的行业与预算告诉我们,免费获取一份量身定制的官网建设方案与报价。

立即免费咨询