【Flink博客阅读】 Flink Runtime 核心机制剖析-读后总结

Flink Runtime 核心机制剖析 读后总结
从这篇文章里面可以主要解释了以下的问题:

Flink整体是一个什么样的架构?

master-slave

Flink 执行过程中有哪些组件?

  • Master

    • Dispatcher 负责接收用户提供的作业,并且负责为这个新提交的作业拉起一个新的 JobManager 组件。
    • ResourceManager 负责资源的管理,在整个 Flink 集群中只有一个 ResourceManager。
    • JobManager 负责管理作业的执行,在一个 Flink 集群中可能有多个作业同时执行,每个作业都有自己的 JobManager 组件。
  • Slave

    • TaskManager 负责提供具体的资源并实际执行作业。

一个作业是如何提交到Flink上并被执行的?

  1. 当用户提交作业的时候,提交脚本会首先启动一个 Client进程负责作业的编译与提交。

  2. 它首先将用户编写的代码编译为一个 JobGraph,在这个过程,它还会进行一些检查或优化等工作,例如判断哪些 Operator 可以 Chain 到同一个 Task 中。

  3. 然后,Client 将产生的 JobGraph 提交到集群中执行。

    此时有两种情况:

    • 一种是类似于 Standalone 这种 Session 模式,AM (Application Master - Yarn术语)会预先启动,此时 Client 直接与 Dispatcher 建立连接并提交作业即可。

    • 另一种是 Per-Job 模式,AM 不会预先启动,此时 Client 将首先向资源管理系统 (如Yarn、K8S)申请资源来启动 AM,然后再向 AM 中的 Dispatcher 提交作业。

  4. 当作业到 Dispatcher 后,Dispatcher 会首先启动一个 JobManager 组件,然后 JobManager 会向 ResourceManager 申请资源来启动作业中具体的任务。

  5. 这时根据 Session 和 Per-Job 模式的区别, TaskExecutor 可能已经启动或者尚未启动。

    • 如果是前者,此时 ResourceManager 中已有记录了 TaskExecutor 注册的资源,可以直接选取空闲资源进行分配。

    • 否则,ResourceManager 也需要首先向外部资源管理系统申请资源来启动 TaskExecutor,然后等待 TaskExecutor 注册相应资源后再继续选择空闲资源进程分配。目前 Flink 中 TaskExecutor 的资源是通过 Slot 来描述的,一个 Slot 一般可以执行一个具体的 Task,但在一些情况下也可以执行多个相关联的 Task,这部分内容将在下文进行详述。

  6. ResourceManager 选择到空闲的 Slot 之后,就会通知相应的 TM “将该 Slot 分配分 JobManager XX ”,然后 TaskExecutor 进行相应的记录后,会向 JobManager 进行注册。

  7. JobManager 收到 TaskExecutor 注册上来的 Slot 后,就可以实际提交 Task 了。

  8. TaskExecutor 收到 JobManager 提交的 Task 之后,会启动一个新的线程来执行该 Task。Task 启动后就会开始进行预先指定的计算,并通过数据 Shuffle 模块互相交换数据。

逻辑执行图是如何转化为物理执行图的?

JobGraph是一种逻辑图结构,不考虑并发。

而ExecutionGraph 是将JobGraph 按并发展开所形成的物理结构,它是 JobMaster 中的核心数据结构。

Flink 作业执行深度解析

物理执行图是怎么调度的?

  • 当 JobManger 来为特定 Task 申请资源的时候,根据当前是 Per-job 还是 Session 模式,ResourceManager 可能会去申请资源来启动新的 TaskExecutor。

  • 当 TaskExecutor 启动之后,它会通过服务发现找到当前活跃的 ResourceManager 并进行注册。在注册信息中,会包含该 TaskExecutor中所有 Slot 的信息。

  • ResourceManager 收到注册信息后,其中的 SlotManager 就会记录下相应的 Slot 信息。当 JobManager 为某个 Task 来申请资源时, SlotManager 就会从当前空闲的 Slot 中按一定规则选择一个空闲的 Slot 进行分配。

  • 当分配完成后,RM 会首先向 TaskManager 发送 RPC 要求将选定的 Slot 分配给特定的 JobManager。**TaskManager 如果还没有执行过该 JobManager 的 Task 的话,它需要首先向相应的 JobManager 建立连接,然后发送提供 Slot 的 RPC 请求。**在 JobManager 中,所有 Task 的请求会缓存到 SlotPool 中。当有 Slot 被提供之后,SlotPool 会从缓存的请求中选择相应的请求并结束相应的请求过程。

  • 当 Task 结束之后,无论是正常结束还是异常结束,都会通知 JobManager 相应的结束状态,然后在 TaskManager 端将 Slot 标记为已占用但未执行任务的状态。

Slot的特殊处理与特性?为了解决什么问题?

  • 【slot延迟释放逻辑】JobManager 会首先将相应的 Slot 缓存到 SlotPool 中,但不会立即释放。这种方式避免了如果将 Slot 直接还给 ResourceManager,在任务异常结束之后需要重启时,需要立刻重新申请 Slot 的问题。通过延时释放,Failover 的 Task 可以尽快调度回原来的 TaskManager,从而加快 Failover(故障转移) 的速度。

  • 【slot实际释放逻辑】当 SlotPool 中缓存的 Slot 超过指定的时间仍未使用时,SlotPool 就会发起释放该 Slot 的过程。与申请 Slot 的过程对应,SlotPool 会首先通知 TaskManager 来释放该 Slot,然后 TaskExecutor 通知 ResourceManager 该 Slot 已经被释放,从而最终完成释放的逻辑。

  • 【slot心跳逻辑】除了正常的通信逻辑外,在 ResourceManager 和 TaskExecutor 之间还存在定时的心跳消息来同步 Slot 的状态。在分布式系统中,消息的丢失、错乱不可避免,这些问题会在分布式系统的组件中引入不一致状态,如果没有定时消息,那么组件无法从这些不一致状态中恢复。此外,【slot心跳丢失】当组件之间长时间未收到对方的心跳时,就会认为对应的组件已经失效,并进入到 Failover 的流程。

  • 【Share 与 Task关系】在 Slot 管理基础上,Flink 可以将 Task 调度到相应的 Slot 当中。如上文所述,Flink 尚未完全引入细粒度的资源匹配,**默认情况下,每个 Slot 可以分配给一个 Task。**但是,这种方式在某些情况下会导致资源利用率不高。

Flink的调度策略?流批处理的策略有什么不同?为什么?

Flink 提供了两种基本的调度逻辑,即 Eager 调度与 Lazy From Source。

  • Eager 调度如其名子所示,它会在作业启动时申请资源将所有的 Task 调度起来。这种调度算法主要用来调度可能没有终止的流作业。适用于流作业。因为流作业需要所有的算子同时启动。

  • 与之对应,Lazy From Source 则是从 Source 开始,按拓扑顺序来进行调度。简单来说,Lazy From Source 会先调度没有上游任务的 Source 任务,当这些任务执行完成时,它会将输出数据缓存到内存或者写入到磁盘中。然后,对于后续的任务,当它的前驱任务全部执行完成后,Flink 就会将这些任务调度起来。这些任务会从读取上游缓存的输出数据进行自己的计算。这一过程继续进行直到所有的任务完成计算。适用于批作业。

Task执行异常的每种错误恢复策略适用的场景?

策略 描述 适用场景
Restart-all 直接重启所有的 Task 流作业
Restart-individual 只重启出现错误的 Task 适用于Task之间没有数据传输
Restart-Base 某个 Region 中的某个 Task 执行出现错误,根据情况只启动部分Region

【Region】: ExecutionGraph 中使用 Pipeline 方式传输数据的 Task 的子图叫做 Region**

Master异常的恢复策略?以及选主算法?

【选主算法】: 通过 ZK 来进行选主,从而保证某一时刻只有一个 Master 在运行

【恢复策略】: 重启Master

后面的源码分析也将按照以上问题展开分析。

你可能感兴趣的:(Flink实战)