Flink-4

  • Flink运行机制
  • 运行时组件
  • 任务提交流程
  • 任务调度原理
  • 程序和数据流(DataFlow)
  • 执行图(ExecutionGraph)
  • 数据传输形式
  • 任务链(Operator Chains)
  • 一致性检查点(checkpoint)
  • 检查点原理
  • 检查点配置
  • 重启策略
  • 保存点(savepoints)


Flink运行机制

运行时组件

flink创建检查点目录失败 flink检查点算法_flink


JobManager

  • 控制一个应用程序执行的主进程;
  • JobManager会先接收到要执行的应用程序,这个应用程序会包括:作业图(JobGraph)、逻辑数据流程图(Logical dataflow graph)和打包了所有的类、库和其他资源的JAR包;
  • JobManager会把JobGraph转换成一个数据流图,这个图被叫做“执行图”(ExecutionGraph),包含了所有可以并发执行的任务;
  • 像资源管理器(ResourceManager)请求执行任务必要的资源,也就是任务管理器(TaskManager)上的插槽(Slot)。一旦获取到了足够的资源,就会将执行图分发到真正运行他们的TaskManager上。而在运行过程中,JobManager会负责将所有需要中央协调的操作,比如检查点(CheckPoint)的协调。

TaskManager

  • Flink中的工作进程。通常在Flink中会有多个TaskManager运行,每一个TaskManager都包含了一定数量的插槽(slots)。插槽的数量限制了TaskManager能够执行的任务数量;
  • 启动之后,TaskManager会向资源管理器注册它的插槽;收到资源管理器的指令后,TaskManager就会将一个或者多个插槽提供给JobManager调用。JobManger就可以向插槽分配任务(tasks)来执行;
  • 在执行过程中,一个TaskManager可以跟它运行统一应用程序的TaskManager交换数据。

ResourceManager

  • 主要负责管理任务管理器(TaskManager)的插槽(slot),TaskManager插槽是Flink中定义的处理资源的单元;
  • Flink为不同的环境和资源管理工作提供了不同的资源管理器,比如Yarn、Mesos、K8s,以及standalone部署;
  • 当JobManager申请插槽资源时,ResourceManager会将有空闲插槽的TaskManager分配给JobManager。如果ResourceManager没有足够的插槽来满足JobManager的请求,它还可以向资源提供平台发起会话,以提供启动TaskManager进程的容器。

Dispacher

  • 可以跨作业运行,它为应用提交提供了REST接口;
  • 当一个应用被提交执行时,分发器就会启动并将应用移交给一个JobManager;
  • Dispacher也会启动一个Web UI,用来方便地展示和监控作业执行的信息;
  • Dispacher在架构中可能并不是必须的,这取决于应用提交运行的方式。

任务提交流程

总体运行流程

flink创建检查点目录失败 flink检查点算法_检查点_02

  1. 通过Web UI或者命令函提交Job给Dispacher;
  2. 启动JobManager并将任务发送给JobManager;
  3. JobManager分析任务,并获取执行图(ExecutionGraph),判断需要多少slot执行任务,向ResourceManager申请slot;
  4. ResourceManager启动TaskManager;
  5. TaskManager获取本机可用的slot,并在ResourceManager上注册;
  6. ResourceManager向TaskManager发出提供slot的指令;
  7. TaskManager将slot提供给JobManager;
  8. JobManager将任务分发到各个slot,并发回TaskManager;
  9. 各个slot被用作计算,TaskManager之间可能存在数据交互(shuffle)。

Yarn模式(Per-Job)运行流程

flink创建检查点目录失败 flink检查点算法_flink_03


这里的ResourceManager是Yarn的ResourceManager

任务调度原理

flink创建检查点目录失败 flink检查点算法_大数据_04

  • 并行度:一个特定算子的子任务(subtask)的个数被称之为并行度(parallelism)。一般情况下,一个stream的并行度,可以认为就是其所有算子中的最大并行度
  • Flink中每个TaskManager都是一个JVM进程,它可能会在独立的线程上执行一个或多个子任务
  • 为了控制一个TaskManager能接收多少个task,TaskManager通过task slot来进行控制(一个TaskManager至少有一个slot),可以在配置文件flink-conf.yaml中的taskmanager.numberOfTaskSlots项目修改配置数量

程序和数据流(DataFlow)

所有Flink程序都由三部分组成:Source、Transformation和Sink。

Source负责读取数据源,Transformation利用各种算子进行处理加工,Sink负责输出。

在运行时,Flink上运行的程序会被映射成“逻辑数据流”,它包含了以上的三个部分。

每个dataflow都以一个或多个source开始以一个或多个sink结束。dataflow类似于任意的有向无环图(DAG)。

大部分情况下,程序中的转换运算跟dataflow中的算子是一一对应关系。

执行图(ExecutionGraph)

Flink中的执行图可以分为四层:StreamGraph->JobGraph->ExecutionGraph->物理执行图

StreamGraph:是根据用户通过StreamAPI编写的代码生成的最初的图。用来标识程序的拓扑结构。

JobGraph:StreamGraph经过优化后生成了JobGraph,提交给JobManager的数据结构。主要优化为,将多个符合条件的节点chain在一起作为一个节点

ExecutionGraph:JobManager根据JobGraph生成ExecutionGraph。ExecutionGraph是JobGraph的并行化版本,是调度层最核心的数据结构。

物理执行图:JobManager根据ExecutionGraph对Job进行调度后,在各个TaskManager上部署Task后形成的“图”,并不是一个具体的数据结构

flink创建检查点目录失败 flink检查点算法_flink_05

数据传输形式

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

任务链(Operator Chains)

  • Flink采用了一种称为任务链的优化技术(类似于Spark的血缘关系),可以在特定条件下减少本地通信的开销。为了满足任务链的要求,必须将两个或多个算子设为相同的并行度,并通过本地转发(local forward)的方式进行连接
  • 相同并行的的one-to-one操作,Flink这样相连的算子链接在一起形成一个task,原来的算子成为里面的subtask
  • 并行度相同、并且是One-to-one操作,两个条件缺一不可
  • 如果任务链中某项任务特别大,希望将其拆分的话,可以指定其中适当的算子调用disableChaining()方法拆分(会被拆分为三个,前面部分、调用方法的算子、后面部分),调用该方法的算子前后部分会被分别放到不同的任务中
  • 如果不想将某个算子单独切分出来,只想将任务前后切分,可以在切分位置后面的一个算子调用startNewChain()方法,开启一个新的任务
  • slotSharingGroup("groupNameA")方法可以指定该算子后之后算子的slot共享组,不设置共享组的话,所有算子默认在一个共享组中,这个共享组的名称为default
  • 全局禁止任务链,使用env对象调用disableChaining()方法

一致性检查点(checkpoint)

应用状态的一致性检查点是Flink故障恢复机制的核心,有状态流应用的一致检查点,起始就是所有任务的状态,在某个时间点的一份拷贝;这个时间点,应该是所有任务都恰好处理完一个相同的输入数据的时候

在执行流应用程序期间,Flink会定期保存状态的一致检查点,如果发生故障,Flink将会使用最近的检查点来一致恢复应用程序的状态,并重新启动处理流程,这种检查点的保存和恢复机制可以为应用程序状态提供“精确一次”(exactly-once)的一致性,因为所有算子都会保存检查点并恢复其所有状态,这样一来所有的输入流就都会被重置到检查点完成时的位置

检查点原理

Flink的检查点设置是一种基于Chandy-Lamport算法的分布式快照,可以将检查点的保存和数据处理分离开,不需要暂停整个应用

Flink的检查点算法用到了一种称为分界线(barrier)的特殊数据形式,用来把一条流上的数据按照不同的检查点分开

分界线之前到来的数据导致的状态更改,都会把包含在当前分界线所属的检查点中;而基于分界线之后的数据导致的所有更改,都会被包含在之后的检查点中

现在是一个有两个输出流的应用程序,用并行的两个source任务来读取、处理并写出数据

flink创建检查点目录失败 flink检查点算法_实时大数据_06


当达到设置的检查点保存间隔时间是,JobManager会向每个source任务发送一条带有新检查点ID的消息(图中三角形的消息),通过这种方式来启动检查点

flink创建检查点目录失败 flink检查点算法_flink创建检查点目录失败_07


当检查点消息传送到Source时,Source Operator将他们的状态写入检查点,并发出一个检查点barrier

状态后端在状态存入检查点之后,会返回通知给source任务,source任务会向JobManager确认检查点完成

数据源在保存状态的同时,后来的数据不能被处理,会被暂存起来,等待状态保存完成后处理

flink创建检查点目录失败 flink检查点算法_flink创建检查点目录失败_08


分界线对齐:检查点不同于普通消息,在re-distributed过程中并不是只发送某一个下游的Operator,而是通过广播的方式发送给下游所有的Operator,对于下游的Operator,只有所有上游发送的barrier都接收到,且barrier前面的数据均已处理过后,才可以开始保存检查点。

以下图为例,barrier向下游传递,sum任务会等待所有输入分区的barrier到达,才会去保存检查点。对于barrier已经到达的分区,继续到达的数据会被缓存,而barrier尚未到达的分区,数据会被正常处理。

这样做的目的是为了保证检查点保存信息时间的统一,防止上游数据在传往下游的过程中迟到。在下图中,Sum even算子收到了蓝色的检查点消息,则可认为本次检查点保存操作中Source 1的数据已经处理完成了,但是仍为收到Source 2的检查点消息,所以此时不能开始检查点保存操作。

flink创建检查点目录失败 flink检查点算法_大数据_09


当Operator收到所有输入分区的barrier(检查点消息)时,任务就将其状态保存到状态后端的检查点中,然后将barrier继续向下游转发

flink创建检查点目录失败 flink检查点算法_实时大数据_10


Sink任务保存完成后,也会向JobManager确认状态保存到checkpint完毕,当所有任务都确认已成功将状态保存到检查点时,检查点保存就真正完成了

flink创建检查点目录失败 flink检查点算法_flink创建检查点目录失败_11

检查点配置

/*开启check,可以调用空参,也可以传入一个毫秒数(时间间隔),如果不传入参数,默认值也是500,
还可以传入第三个参数,表示状态一致性的级别,默认exactly once*/
env.enableCheckpointing()
val conf = env.getCheckpointConfig //获取checkpoint配置,再通过配置对象调用set方法进行设置
conf.setCheckpointingMode(CheckpointingMode.AT_LEAST_ONCE) //设置一致性级别
conf.setCheckpointTimeout(60000L) //设置超时时间
conf.setMaxConcurrentCheckpoints(2)//运行同时并行多少个checkpoint,默认是1个
/*两次checkpoint之间最小间歇时间,即前面一次barrier完成到下一个barrier开始之间的最小间隔时间,
如果操作时间小于设置的最小间隔时间,下次操作将会被推迟直到满足要求,会覆盖掉并行设置*/
conf.setMinPauseBetweenCheckpoints(2000)
//设置是否更倾向于使用checkpoint恢复,如果savepoint比checkpoint更接近实际情况,则使用savepoint
conf.setPreferCheckpointForRecovery(true)
conf.setTolerableCheckpointFailureNumber(3)//设置容忍checkpoint失败次数

重启策略

两种常用的重启策略

env.setRestartStrategy(RestartStrategies.fixedDelayRestart(3,10000L))
env.setRestartStrategy(RestartStrategies.failureRateRestart(5,Time.of(5,TimeUnit.MINUTES),Time.of(10,TimeUnit.SECONDS)))

保存点(savepoints)

  • Flink还提供了可以自动的镜像保存功能,就是保存点(savepoint)
  • 原则上,创建保存点使用的算法与检查点完全相同,因此保存点可以认为就是具有一些额外元数据的检查点
  • Flink不会自动创建保存点,因此用户(或者外部调度程序)必须明确地触发创建操作
  • 保存点是一个强大的功能,处理故障恢复外,保存点可以用于:有计划的手动备份,更新应用程序,版本迁移,暂停和重启应用等,最好调用.uid(n)方法手动设定版本号