Fl一文吃透 Flink Jobs and Scheduling从资源调度到失败恢复
一、为什么要理解 Flink 的 Jobs and Scheduling很多人刚接触 Flink 时会把它理解成“提交一个 Jar然后集群帮我跑起来”。但实际上Flink 在运行一个作业时内部会做很多复杂工作解析数据流图计算并行度划分任务执行单元分配 Slot构建并行执行图跟踪每个子任务状态处理失败、取消、重启、恢复这些动作并不是“附属功能”而是 Flink 能够支撑大规模实时计算的基础能力。你可以把它理解成这样JobGraph像是“施工蓝图”ExecutionGraph像是“真正施工时拆分到每一个工位的执行计划”Task Slot像是“工位资源”Job 状态机像是“项目整体进度”Task 状态机像是“每个施工工人的当前工作状态”理解这套机制后你再去看 Flink Web UI、日志、失败栈、重启过程就不会只停留在“任务挂了”这种表层认知而是能清楚知道是谁在运行、运行在哪、为什么没被调度、失败后会不会自动恢复、当前到底是 Job 失败了还是某个 Execution 在重试。二、Flink 调度的核心起点Task SlotFlink 的执行资源是通过Task Slot来定义的。简单来说一个TaskManager可以配置一个或多个Task Slot一个 Slot 可以运行一个并行任务流水线pipeline这个流水线里可能包含多个可以链式或共享资源执行的连续任务也就是说Slot 并不是只能跑单个算子而是可以承载一条由多个子任务组成的执行链路。1. 什么是 Pipeline在 Flink 中一个 pipeline 可以看作是一组可以连续执行的并行任务组合。例如有这样一个数据处理链路SourceMapReduce如果 Source 和 Map 的并行度是 4Reduce 的并行度是 3那么 Flink 会根据算子之间的数据交换关系、并行度和调度约束去决定哪些任务实例可以组成一个 pipeline并把它们分配到不同 Slot 中执行。这就是为什么在 Flink 中我们经常会看到某些算子能够串在一起执行某些算子必须经过网络 shuffle某些任务可以共享 Slot某些任务必须单独占用资源2. SlotSharingGroup 与 CoLocationGroupFlink 内部通过两类机制控制任务的 Slot 使用策略SlotSharingGroup它定义的是哪些任务“允许”共享同一个 Slot这是一个比较“宽松”的约束。只要属于同一个 SlotSharingGroup理论上这些任务就可以被调度到同一个 Slot 内从而提升资源利用率。这在流处理任务中非常常见因为上下游链式执行可以显著减少网络传输和调度开销。CoLocationGroup它定义的是哪些任务“必须”严格放在同一个 Slot 中这比 SlotSharingGroup 更强是一种强绑定关系。通常用于一些必须保持位置对应关系的场景比如迭代计算、严格一一对应的上下游任务。3. 图示任务流水线如何分配到 Slot你可以在博客中配上类似说明图中展示了在 2 个 TaskManager、每个 TaskManager 3 个 Slot 的情况下Source、Map、Reduce 不同并行实例如何组合成 pipeline并最终映射到不同的 Slot 上执行。4. 这对生产环境意味着什么很多线上问题本质上都和 Slot 调度有关作业提交后一直处于等待调度状态某些任务明明资源够但就是起不来算子链路太长某个 Slot 压力过大SlotSharing 设置不合理导致资源竞争严重某些批任务因为上下游不能共享 Slot导致资源需求突然膨胀所以理解 Slot并不是理解一个“名词”而是理解 Flink 资源调度的第一层入口。三、JobManager 眼中的作业从 JobGraph 到 ExecutionGraph当用户提交一个 Flink 作业时JobManager 并不是直接拿着用户代码执行而是先构建和维护一套内部数据结构用来管理整个作业的运行过程。这其中最重要的两个结构就是JobGraphExecutionGraph很多初学者容易把这两个概念混淆。其实它们分别对应的是两个不同层次的视角。四、JobGraph逻辑层的数据流表示JobManager 接收到的是一个JobGraph。你可以把 JobGraph 理解为一个描述“这个作业要做什么”的逻辑执行图它主要由两类元素构成JobVertex表示算子节点IntermediateDataSet表示算子之间的中间结果集每个 JobVertex 会携带这个算子的关键信息例如算子代码并行度算子配置依赖关系此外JobGraph 还会包含作业运行所需要的附加库也就是执行这些算子所依赖的 Jar、Class、资源等。1. JobGraph 的特点JobGraph 更偏向“逻辑视图”它关注的是作业有哪些算子算子之间如何连接每个算子的并行度是多少数据是如何在算子之间流动的但 JobGraph 还没有真正展开到“每个并行子任务实例”。比如一个并行度为 100 的算子在 JobGraph 中仍然只是一个 JobVertex这也是 JobGraph 和 ExecutionGraph 最大的区别所在。五、ExecutionGraph真正用于执行的并行化运行图JobManager 会把 JobGraph 转换成ExecutionGraph。ExecutionGraph 可以理解为JobGraph 的并行化、运行时版本如果说 JobGraph 是“设计图”那么 ExecutionGraph 就是“施工展开图”。1. ExecutionVertex每个并行子任务都有独立状态在 ExecutionGraph 中每个 JobVertex 会被展开成多个ExecutionVertex每个 ExecutionVertex 对应一个并行子任务实例例如一个算子并行度为 100JobGraph 中只有 1 个 JobVertexExecutionGraph 中会有 100 个 ExecutionVertex这些 ExecutionVertex 才是真正被调度、运行、失败、恢复的最小执行单元。2. ExecutionJobVertex算子整体视图所有属于同一个 JobVertex 的 ExecutionVertex会被组织在一个ExecutionJobVertex中。它的作用相当于从“整个算子”的维度统一跟踪所有并行子任务的状态也就是说JobVertex 是逻辑定义ExecutionJobVertex 是运行时的算子实例集合ExecutionVertex 是真正的单个并行子任务3. IntermediateResult 与 IntermediateResultPartition除了 Vertex 以外ExecutionGraph 中还会维护中间结果相关的运行时对象IntermediateResult跟踪一个中间结果集的整体状态IntermediateResultPartition跟踪每一个分区的状态为什么要分这么细因为 Flink 的上游结果往往不是一个整体文件而是按照并行度切分成多个 partition。下游在消费数据时也不是“拿一个完整结果”而是会消费这些 partition。这对于以下场景尤其重要shuffle 数据交换批任务阶段性调度失败恢复时的分区重用或重新生成上下游依赖关系判断4. 图示JobGraph 与 ExecutionGraph 的关系配图说明建议这样写左侧是逻辑层的 JobGraph包含 A、B、C、D 等 JobVertex 以及中间数据集右侧是展开后的 ExecutionGraph每个 JobVertex 被拆分成多个 ExecutionVertex中间结果也被细化为多个 IntermediateResultPartition。5. 为什么这部分很关键很多人查线上问题时只会看“这个算子失败了”。但 Flink 真正运行的时候失败的并不是抽象意义上的“算子”而是某个ExecutionVertex对应当前一次具体尝试的 Execution这意味着你在分析问题时要能区分是整个 JobVertex 出问题还是某个并行子任务出问题是某个 partition 卡住了还是整个上游 IntermediateResult 没准备好理解了 ExecutionGraph很多 Flink Web UI 里的执行视图和日志信息就会一下子清晰起来。六、Flink Job 的全局状态机作业从提交到终止经历了什么每个 ExecutionGraph 都会对应一个JobStatus也就是整个作业的全局状态。这套状态机描述的是一个 Flink Job 从被创建开始到运行、失败、取消、重启、结束的完整生命周期。1. 正常执行路径一个 Flink Job 最正常的状态流转路径是CREATEDRUNNINGFINISHED含义分别是CREATED作业已经创建但还没有真正开始稳定运行。这个阶段更多是作业刚被接收、图结构建立、准备进入执行流程的状态。RUNNING作业已经进入实际执行阶段任务正在运行。FINISHED所有工作都已经完成作业正常结束。这个状态是全局终态之一。2. 失败路径当作业运行过程中出现故障时Job 并不是立刻变成 FAILED而是会先经历一个中间阶段FAILINGFAILED或RESTARTING这点很重要。FAILING进入 FAILING 状态时Flink 会先取消所有还在运行的任务。也就是说这个阶段本质上是在做“失败收敛”。FAILED如果当前作业不可重启或者已经不满足重启条件那么当所有相关任务都进入终态后作业最终进入 FAILED。这是一个全局终态。RESTARTING如果当前作业配置了可用的重启策略并且仍然允许重启那么作业不会直接 FAILED而是进入 RESTARTING。待整个作业完成重启流程后又会重新回到 CREATED然后再次进入 RUNNING。这也是为什么你有时候会在 Web UI 中看到 Job 在FAILINGRESTARTINGCREATEDRUNNING之间来回切换。3. 用户取消路径如果不是系统失败而是用户主动取消任务那么作业状态会走另一条路径CANCELLINGCANCELEDCANCELLING正在取消中。Flink 会停止并清理所有正在运行的任务。CANCELED所有相关任务都已经完成取消作业进入取消完成状态。这同样是一个全局终态。4. 特殊状态SUSPENDED除了 FINISHED、CANCELED、FAILED 这些全局终态外Flink 还有一个很特别的状态SUSPENDED这个状态不是全局彻底结束而是局部终态locally terminal。什么意思它表示当前 JobManager 上这个作业已经终止执行但作业并没有被完全清理掉。因为在开启 HA高可用时其他 JobManager 仍然可以从持久化的 HA 存储中恢复这个作业并重新启动它。所以FAILED / FINISHED / CANCELED通常意味着全局结束触发作业清理SUSPENDED只是当前 JobManager 本地结束不代表整个作业彻底消失这个概念对于理解 Flink HA 模式下的主备切换特别关键。5. 图示Flink Job 状态流转图你可以在图下方补一句说明该图展示了 Flink Job 从 CREATED、RUNNING 到 FINISHED 的正常路径以及 FAILING、RESTARTING、CANCELLING、CANCELED、FAILED、SUSPENDED 等异常和控制类状态之间的转换关系。七、为什么 Job 状态机很重要理解 Job 状态机后你在生产环境中看任务状态时就不会只停留在“运行中”和“失败了”。例如1. 为什么任务不是直接 FAILED而是先 FAILING因为 Flink 不是简单地“发现异常就退出”而是要先把所有相关运行中的任务收敛到一个可控状态避免系统处于半执行、半失败的混乱中。2. 为什么有时候任务失败后又自己好了因为任务可能启用了重启策略Job 在 FAILED 之前先走了 RESTARTING恢复成功后重新进入 RUNNING。3. 为什么 HA 场景下任务没了但又能回来因为作业可能进入的是 SUSPENDED而不是 FAILED。SUSPENDED 说明当前 JobManager 不继续跑了但作业元信息还在其他 JobManager 可以接手恢复。八、Task 级别的生命周期Execution 才是最细粒度的执行单元如果说 JobStatus 描述的是整个作业的状态那么 Task 级别的状态机描述的就是一个具体并行子任务是如何被创建、部署、初始化、运行、取消、失败、结束的。这部分非常重要因为真正发生故障时最先出问题的往往不是整个 Job而是某个具体的 Task Execution。1. ExecutionVertex 与 Execution 的关系前面说过ExecutionVertex表示一个并行子任务实例Execution表示这个子任务某一次具体执行尝试为什么要引入 Execution因为一个子任务可能不是只执行一次。比如第一次执行时失败了触发重启第二次重新执行再失败第三次恢复成功此时ExecutionVertex 还是同一个逻辑子任务但它会关联多个不同历史时期的 Execution所以Execution 是 Flink 用来跟踪“某个子任务某一次具体执行过程”的对象。这也是 Flink 故障恢复机制能细粒度追踪尝试次数的基础。九、Task Execution 的状态流转过程在运行过程中一个 Execution 通常会经历以下状态CREATEDSCHEDULEDDEPLOYINGINITIALIZINGRUNNINGFINISHED如果发生异常或人为干预则还可能进入CANCELINGCANCELEDFAILED1. CREATEDExecution 刚刚被创建还未调度到具体资源上。2. SCHEDULED已经完成调度决策准备分配资源并下发执行。3. DEPLOYING正在将任务部署到对应的 TaskManager 上。4. INITIALIZING任务已经开始初始化运行环境比如恢复状态初始化算子实例建立输入输出通道做启动前准备5. RUNNING真正进入运行状态开始处理数据。6. FINISHED执行正常结束。这是该次 Execution 的终态之一。7. CANCELING / CANCELED如果任务被取消会先进入 CANCELING再进入 CANCELED。8. FAILED如果任务在执行过程中发生异常进入 FAILED。这也是单次 Execution 的终态之一。十、图示Task Execution 的完整状态机这里建议插入你提供的第四张图。图下说明可以这样写该图展示了一个 Task Execution 从创建、调度、部署、初始化到运行、完成的正常路径以及在取消、失败等异常情况下的状态流转过程。由于一个 ExecutionVertex 可以多次执行因此同一个子任务会经历多个不同的 Execution 实例。十一、Job 状态机和 Task 状态机有什么区别很多人第一次看 Flink 状态图时会疑惑Job 不是已经有状态了吗为什么 Task 还有一套状态这里一定要区分清楚Job 状态机关注的是整个作业当前所处的全局阶段比如RUNNINGFAILINGRESTARTINGCANCELEDTask 状态机关注的是单个子任务当前执行到哪一步了比如DEPLOYINGINITIALIZINGRUNNINGFAILED可以这样理解Job 状态是“项目总进度”Task 状态是“每个工位上的工人干到哪一步了”一个 Job 进入 FAILING通常意味着其中某些 Task Execution 已经 FAILEDJobManager 正在协调整个作业进入统一失败处理流程。十二、一个完整的故障恢复过程是怎样发生的为了帮助大家把这些概念串起来我们来看一个典型场景。假设某个 Flink 流任务正在运行某个下游算子其中一个并行子任务突然抛出异常。此时内部大致会发生这样的事情第一步某个 Execution 失败某个 ExecutionVertex 当前关联的 Execution 进入 FAILEDJobManager 收到失败事件第二步Job 进入 FAILINGJobManager 判断这是影响整个作业一致性的故障ExecutionGraph 对应的 JobStatus 切换到 FAILING系统开始取消其他相关运行中任务第三步判断是否可重启如果配置了合适的 Restart Strategy且未超过阈值Job 进入 RESTARTING否则Job 进入 FAILED第四步重新创建执行流程如果可重启Job 完成失败清理重新回到 CREATED重新调度Task 重新经历 SCHEDULED、DEPLOYING、INITIALIZING、RUNNING第五步恢复成功或再次失败如果恢复成功Job 回到 RUNNING如果再次失败继续重复失败恢复链路直到成功或不再允许重启这就是为什么你在实际日志里可能会看到某个 task failedjob switched from RUNNING to FAILINGrestarting jobreset execution graphscheduling tasksdeploying tasktask switched to RUNNING这些日志如果单独看会很碎但你一旦掌握 JobGraph、ExecutionGraph、JobStatus、Execution 状态机就会发现整个过程其实非常清晰。十三、这些底层机制对排障有什么帮助理解这套调度和状态机制后你在线上排查问题时会非常有用。1. 作业长时间不运行优先看Job 是否一直停留在 CREATED / SCHEDULED是否存在 Slot 不足是否有 SlotSharingGroup / CoLocationGroup 导致调度受限是否某些上游中间结果未准备完成2. 作业频繁重启优先看Job 是否在 RUNNING → FAILING → RESTARTING 之间循环是哪个 ExecutionVertex 反复失败是状态恢复失败还是业务算子异常是否超过重启策略阈值3. 某个算子看起来“偶发挂掉”不要只看 JobVertex 名称要继续下钻是哪个并行子任务失败当前是第几次 Execution是否与某个特定 partition、数据分片、节点资源有关4. HA 场景下任务异常消失要区分是 FAILED还是 SUSPENDED如果是 SUSPENDED说明还有可能被其他 JobManager 接管恢复。十四、面向生产环境的几个理解建议1. 不要只从“算子视角”看 Flink很多人写代码时脑子里只有SourceMapKeyByWindowSink但运维和排障时你必须切换到JobGraphExecutionGraphExecutionVertexIntermediateResultPartitionJobStatusExecution State这才是 Flink 真正运行时的世界。2. Web UI 上看到的不是“抽象任务”而是运行时结构的映射你在 Flink UI 中看到的Job 状态Vertex 视图子任务视图并行实例失败重启次数本质上都是 JobManager 内部这些运行时数据结构的外在展示。3. 调度问题、失败恢复问题、性能问题本质都和 ExecutionGraph 有关因为真正被调度的是它真正失败和恢复的也是它。十五、总结理解 Flink 执行机制才能真正驾驭生产任务很多人学习 Flink 时只关注 API 怎么写、SQL 怎么调优但一旦进入生产环境你会发现真正决定你技术深度的是你是否理解 Flink 的运行时机制。这篇文章我们系统梳理了几个核心点Task Slot是 Flink 资源调度的基础单位Pipeline表示可在同一执行链中运行的一组并行任务SlotSharingGroup控制哪些任务可以共享 SlotCoLocationGroup控制哪些任务必须严格同槽部署JobGraph是逻辑层执行图ExecutionGraph是并行化后的运行时执行图ExecutionVertex是真正的并行子任务实例Execution表示某个子任务的一次具体执行尝试Job 状态机描述整个作业的生命周期Task 状态机描述每个子任务执行实例的生命周期一句话概括就是JobGraph 决定“你要跑什么”ExecutionGraph 决定“具体怎么跑”而 Job/Task 状态机则决定“跑到哪了、出问题怎么恢复”。如果你能把这几层真正吃透那么无论是看 Flink 源码、分析 Web UI、排查线上故障、设计高可用方案都会轻松很多。
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2416311.html
如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!