一. 什么是Flink
- Apache Flink 是一个分布式流处理引擎, 提供了直观且极丰富表达力的Api来实现有状态的流式处理。
-
用于无界和有界数据流上的有状态计算。Flink被设计为在所有常见的集群环境中运行,以内存中的速度和任何规模执行计算。
二.Flink应用场景
A. 事件驱动型应用
- 事件驱动型应用是一类具有状态的应用,它从一个或多个事件流提取数据,并根据到来的事件触发计算、状态更新或其他外部动作。
-
事件驱动型应用无须查询远程数据库,本地数据访问使得它具有更高的吞吐和更低的延迟。
B. 数据分析应用
- 数据分析任务需要从原始数据中提取有价值的信息和指标。
- 传统的分析方式通常是利用批查询,或将事件记录下来并基于此有限数据集构建应用来完成。为了得到最新数据的分析结果,必须先将它们加入分析数据集并重新执行查询或运行应用,随后将结果写入存储系统或生成报告。
- Flink可以实时地进行数据分析。和传统模式下读取有限数据集不同,流式查询或应用会接入实时事件流,并随着事件消费持续产生和更新结果。这些结果数据可能会写入外部数据库系统或以内部状态的形式维护。仪表展示应用可以相应地从外部数据库读取数据或直接查询应用的内部状态。
-
流式分析省掉了周期性的数据导入和查询过程,因此从事件中获取指标的延迟更低。
C. 数据管道应用
- 提取-转换-加载(ETL)是一种在存储系统之间进行数据转换和迁移的常用方法。ETL 作业通常会周期性地触发,将数据从事务型数据库拷贝到分析型数据库或数据仓库。
- 数据管道和 ETL 作业的用途相似,都可以转换、丰富数据,并将其从某个存储系统移动到另一个。但数据管道是以持续流模式运行,而非周期性触发。因此它支持从一个不断生成数据的源头读取记录,并将它们以低延迟移动到终点。
-
和周期性 ETL 作业相比,持续数据管道可以明显降低将数据移动到目的端的延迟。此外,由于它能够持续消费和发送数据,因此用途更广,支持用例更多。
三. Flink特点
- Deploy Applications Anywhere
集成了所有常见的集群资源管理器,如Hadoop YARN、Apache Mesos 和 Kubernetes,也可作为一个独立的集群运行。 - Run Applications at any Scale
设计目的是在任何规模上运行有状态流应用程序。应用程序可能被并行化为数千个任务,这些任务分布在集群中并同时执行。所以应用程序能够充分利用无尽的 CPU、内存、磁盘和网络 IO。而且 Flink 很容易维护非常大的应用程序状态。其异步和增量的检查点算法对处理延迟产生最小的影响,同时保证精确一次状态的一致性。 -
Leverage In-Memory Performance (利用内存性能)
有状态的 Flink 程序针对本地状态访问进行了优化。任务的状态始终保留在内存中,如果状态大小超过可用内存,则会保存在能高效访问的磁盘数据结构中。任务通过访问本地(通常在内存中)状态来进行所有的计算,从而产生非常低的处理延迟。Flink 通过定期和异步地对本地状态进行持久化存储来保证故障场景下精确一次的状态一致性。
四. Flink 组件
A. Flink 基本组件
- Dispatcher:负责接收用户提供的作业,并且负责为这个新提交的作业拉起一个新的 JobManager 服务
- ResourceManager:负责资源的管理,在整个 Flink 集群中只有一个 ResourceManager,资源相关的内容都由这个服务负责 (TaskManager 处理槽)
- JobManager:控控制单个应用的执行,JobManager将JobGraph 转换为 ExecutionGraph. JobManager向ResourceManager申请任务槽,一旦收到足够数量的TaskManager任务槽,就会将ExecutionGraph任务分发给TaskManager。 JobManager 还要负责所有集中需要协调的工作,如创建检查点。
-
TaskManager:是JVM工作进程,每个TaskManager提供一定数量的工作槽
B. JobManager 数据结构
- 在作业执行期间,JobManager 会持续跟踪各个 task,决定何时调度下一个或一组 task,处理已完成的 task 或执行失败的情况
- JobManager 会接收到一个 JobGraph,用来描述由多个算子顶点 (JobVertex) 组成的数据流图,以及中间结果数据 (IntermediateDataSet)。
- JobManager 会将 JobGraph 转成 ExecutionGraph。
- ExecutionVertex 会跟踪子 task 的执行状态。ExecutionJobVertex 持有同一个 JobVertext 的所有 ExecutionVertex ,并跟踪整个算子的运行状态。
C. JobManager & TaskManager
D. Task slot
Task slot: 用于定义执行资源, 一个TaskManager 有一个到多个Task slot
每个Task slot代表TaskManager的资源的固定子集。例如,具有三个插槽的TaskManager会将其托管内存的1/3专用于每个插槽。分配资源意味着子任务不会与其他作业的子任务竞争托管内存,而是具有一定数量的保留托管内存。请注意,此处未发生任何CPU隔离。当前插槽仅将任务的托管内存分开。
对于分布式执行,Flink将操作符子任务连接到一起,形成多个任务。每个任务由一个线程执行。将操作员链接到任务是一个有用的优化:它减少了线程到线程的切换和缓冲的开销,并增加了总体吞吐量,同时减少了延迟。
默认情况下,Flink允许子任务共享插槽,即使它们是不同任务的子任务也是如此,只要它们来自同一作业即可。结果是一个插槽可以容纳整个作业管道。
默认任务链是开启的。
E. 算子、任务、处理槽
F. Job 状态变化
G. Task 状态变化
五. Execution Plan
- 获取执行计划JSON:env.getExecutionPlan()
- 可视化执行计划:https://flink.apache.org/visualizer/
六. DataStream API 与DataSet API区别
DataSet API
- 批式处理,其接口封装类似于Spark的Dataset,支持丰富的函数操作,比如map/fliter/join/cogroup等
- 数据源创建初始数据集,例如来自文件或Java集合等静态数据
- 所有的操作为Operator的子类,实现具体逻辑,比如Join逻辑是在JoinOperator中实现
- Dataset的实现在flink-javamodule中
DataStram API
- 流式处理,其结构封装实现输入流的处理,其也实现了丰富的函数支持
- 所有的操作为StreamOperator的子类,实现具体逻辑,比如Join逻辑是在IntervalJoinOperator中实现的
- DataStream的实现在flink-streaming-java中
七. Flink 时间语义
A. Time时间
- Event Time:事件时间戳可以从每个event中提取。在事件时间,时间的进展取决于数据,而不取决于任何挂钟。事件时间程序必须指定如何生成事件时间水印,这是在事件时间中发出进展信号的机制。
- Ingestion Time:摄入时间是事件进入Flink的时间。在内部,摄取时间与事件时间很相似,但是具有自动时间戳分配和自动水印生成。
- Processing Time:处理时间是指执行相应操作(算子)的机器的系统时间。它提供了最佳的性能和最低的延迟。与事件时间相比,摄取时间程序不能处理任何无序的事件或延迟的数据,但程序不必指定如何生成水印。
B. 事件时间处理
- Timestamps
- Flink事件时间流应用程序处理的所有记录都必须带有时间戳。
- 随着流的前进,流记录的时间戳大致是升序。基本上在所有实际案列中时间戳都会出现一定程度的乱序。
- 当Flink以事件时间模式处理数据流时,它基于记录的时间戳评估基于时间的算子(eg. 窗口算子,会在事件时间超过窗口结束边界时触发计算推动进度前进)。Flink将时间戳编码为16字节长的值,并将它们作为元数据附加到记录中。
- Watermarks
- Watermarks 是一种全局进度度量,它指示我们确信不会再出现延迟事件的时间点。即:Watermarks 时间 T < 接下来接收到的事件时间T'
- Watermarks 允许我们在结果的精确性和延迟之间做出取舍。
- Watermarks 必须是单调递增的。
- 对于事件时间窗口和处理无序事件的算子来说,Watermarks 都是必不可少的。一旦接收到 Watermarks,算子就会被通知某个时间间隔内的所有时间戳都已被观察到,并且要么触发计算,要么接收事件。
C. 分配时间戳与生成水位线
- 水位线用于告诉算子不必再等待那些时间戳小于或等于水位线的事件。
- 水位线和时间戳都是通过自1970-01-01 00:00:00 以来的毫秒数指定。
- 通过SourceFunction分配时间戳及生成水位线
- 时间戳分配及水位线生成器
- 周期性水位分配器 : AssignerWithPeriodicWatermarks (默认 200ms)
- AscendingTimestampExtractor:单调递
- BoundedOutOfOrdernessTimestampExtractor(maxOutOfOrderness):最大允许的乱序时间
- 定点水位分配器: AssignerWithPunctuatedWatermarks
- 周期性水位分配器 : AssignerWithPeriodicWatermarks (默认 200ms)
PS: 时间蹉分配与水位线的生成尽可能的接近数据源。如果某些初始化的过滤或者其他转换操作不会引起元素的重新分发,可以考虑在分配时间戳之前使用它。重新分发可能会导致数据乱序 (keyBy())。
D. 多输入流Watermark
一个任务为它每个输入分区都维护一个分区水位线。当收到某个分区传来的水位线后,会以当前值和接收值较大的去更新相应分区水位线值。然后,任务会把事件时间时钟调整为所有分区水位线中最小的值。
对于有多条输入流的算子(union, coFlatMap),它们的任务也是利用全部分区最小值来计算事件时间时钟的。
E. 处理迟到数据
- 迟到是指元素到达算子后,本应参加与贡献的算子已经计算完成。在事件时间窗口算子的环境下,如果事件时间到达算子时窗口分配器为其分配的窗口已经因为算子水位线超过了它的结束时间而计算完毕,那么事件就是迟到的。
- 通过比较事件时间戳和当前水位线来识别迟到事件。
- 丢弃事件:事件时间窗口默认行为
- 重定向迟到事件:sideOutputLateData(OutputTag<T> outputTag) ;getSideOutput(OutputTag<T> outputTag)
- 基于迟到事件更新结果:对不完整的结果进行重新计算并发出更新
- 算子中保存用于再次计算结果的状态
- 受结果更新影响的下游算子或者外部系统能够处理更新
- 指定延迟容忍度:allowedLateness, 窗口算子在水位线超过窗口结束时间戳之后不会立即删除窗口,而是会将窗口继续保留该延迟容忍度时间。在这段额外时间内到达的迟到元素会像按时到达的元素一样交给触发器处理。水位线超过窗口时间加延迟容忍度间隔,窗口才会被删除,此后所有的迟到数据都会被丢弃。
水位线、延迟及完整性
- 水位线用于平衡延迟和结果的完整性
- 水位线远落后于已处理记录的时间蹉,导致延迟增大,数据准确性较高。
- 生成的水位线过于紧迫,水位线可能大于部分后来的数据的时间蹉,计算可能已经触发,导致数据不够完整和精确,但具体较低的延迟。
八. flink 消息投递机制
At most once 至多一次:随意丢弃事件,没有保障
At least once 至少一次:不丢失事件,事件可能会被处理多次。源头会在缓冲区需要支持重放
Exactly once 精确一次:不丢失事件,每个事件对于内部状态的更新都只有一次。数据重放。(检查点)
九. checkPoint检查点和savePoint保存点
Flink 状态
只有在每一个单独的事件上进行转换操作的应用才不需要状态,换言之,每一个具有一定复杂度的流处理应用都是有状态的。任何运行基本业务逻辑的流处理应用都需要在一定时间内存储所接收的事件或中间结果,以供后续的某个时间点(例如收到下一个事件或者经过一段特定时间)进行访问并进行后续处理。
checkPoint
- 周期性生成,根据配置的策略自动丢弃
- 应用被手动停止后,检查点会被删除。
- 可以通过配置来保留 checkpoint,这些被保留的 checkpoint 在作业失败或取 消时不会被清除
- 保证应用在出现故障时可以顺利重启。
savePoint
- 用户触发,也可周期性生成
- Flink 不会自动清理
- 扩缩容,迁移,暂停应用,应用状态归档,回到过去
Flink checkPoint算法
- Flink 使用 Chandy-Lamport algorithm 算法的一种变体,称为异步 barrier 快照(asynchronous barrier snapshotting)
- 当 checkpoint coordinator(job manager 的一部分)指示 task manager 开始 checkpoint 时,它会让所有 sources 记录它们的偏移量,并将编号的 checkpoint barriers 插入到它们的流中。这些 barriers 流经 job graph,标注每个 checkpoint 前后的流部分。
checkPoint对性能的影响 - Flink 检查点算法能够在不停止整个应用的情况下为流式应用生成一致的分布式检查点,但是会增加应用的处理延迟
- 将状态存入检查点的过程中,会处于阻塞状态,此时的输入会进入缓冲区,由于状态可能非常大,还可能通过网络写入远程存储系统,因此会持续很长一段时间。
- 检查点由状态后端负责生成,具体的拷贝过程由状态后端决定。文件系统状态后端和RocksDB状态后端支持异步生成检查点。当状态后端将当前状态的本地拷贝完成后,任务就可以继续执行。后台进程会异步的将本地状态快照拷贝到远程,然后在完成检查点后通知任务。异步生成检查点可以有效的降低任务恢复数据处理所需要的时间。 RocksDB还可以进行增量生成检查点,可以降低传输的数据量。
- 对于那些需要极低延迟且能容忍至少一次状态保障的应用,可以配置让Flink在分隔符对齐的过程中不缓存那些已经收到分隔符所对应分区的记录,而是直接处理他。
Task 故障恢复之重启策略
- 固定间隔策略 (Fixed delay)
- restart-strategy: fixed-delay
- restart-strategy.fixed-delay.attempts: 3
- restart-strategy.fixed-delay.delay: 10 s
- 失败率策略 (Failure rate)
- restart-strategy: failure-rate
- restart-strategy.failure-rate.max-failures-per-interval: 3
- restart-strategy.failure-rate.failure-rate-interval: 5 min
- restart-strategy.failure-rate.delay: 10 s
- 回退重启策略(Fallback Restart)
- 使用集群定义的重启策略。
- 无重启 (No restart)
- restart-strategy: none