Flink
简单介绍一下 Flink
Flink 是一个框架和分布式处理引擎,用于对无界和有界数据流进行有状态计算。并且 Flink 提供了数据分布、容错机制以及资源管理等核心功能。Flink提供了诸多高抽象层的API以便用户编写分布式任务:
- DataSet API, 对静态数据进行批处 理操作,将静态数据抽象成分布式的数据集,用户可以方便地使用Flink提供的各种操作符对分布式数据集进行处理,支持Java、Scala和Python。
- DataStream API,对数据流进行流处理操作,将流式的数据抽象成分布式的数据流,用户可以方便地对分布式数据流进行各种操作,支持Java和Scala。
- Table API,对结构化数据进行查询操作,将结构化数据抽象成关系表,并通过类SQL的DSL对关系表进行各种查询操作,支持Java和Scala。
此外,Flink 还针对特定的应用领域提供了领域库,例如: Flink ML,Flink 的机器学习库,提供了机器学习Pipelines API并实现了多种机器学习算法。 Gelly,Flink 的图计算库,提供了图计算的相关API及多种图计算算法实现。
Flink的主要特点是什么?
Flink的主要特点包括:
- 流式处理和批处理一体化:Flink既支持流式处理,也支持批处理,可以无缝地在流处理和批处理之间切换。
- 事件驱动的处理模型:Flink使用事件时间和处理时间的概念,支持基于事件的处理和窗口操作,适用于实时数据处理和分析。
- 高性能和低延迟:Flink的优化引擎可以实现高吞吐量和低延迟的数据处理,适用于需要快速响应的应用场景。
- 容错性和可靠性:Flink具有容错机制,可以在节点故障时保证数据处理的正确性和一致性。
- 灵活的编程模型:Flink支持多种编程模型,包括基于流的API(DataStream API)和基于批的API(DataSet API),并提供了多种编程语言接口。
Flink的应用场景有哪些?
Flink 适用于以下应用场景:
- 实时数据处理和分析:Flink 可以处理实时数据流,支持实时数据处理和分析,适用于实时监控、实时报表和实时分析等场景。
- 批处理任务:Flink 可以处理有界数据集,支持批处理任务,适用于离线数据处理和大规模数据分析等场景。
- 基于事件的应用:Flink 的事件驱动处理模型适合构建基于事件的应用,如实时推荐系统、欺诈检测和实时预测等场景。
- 流批一体化应用:Flink 的流批一体化特性使得可以将流式和批式处理结合起来,适用于需要实时和离线处理结合的应用场景。
- 数据挖掘和机器学习:Flink 可以处理大规模的数据集,并支持各种数据挖掘和机器学习算法,适用于构建大规模的数据挖掘和机器学习应用。
- 实时计算和决策:Flink 支持实时计算和决策,可以根据实时数据流进行实时决策和行动,适用于需要实时决策和行动的场景,如实时定价、实时广告投放等。
- 物联网应用:Flink 可以处理大规模的实时数据流,适用于处理物联网应用中的实时数据,如智能家居、智能城市、智能交通等场景。
Flink 是一个通用的大数据处理框架,可 以适用于各种大规模数据处理和分析的场景,尤其适用于需要实时处理和分析的场景。
Flink编程模型是什么?
1)Flink分层模型
Flink底层通过封装和抽象,提供四级分层编程模型,以此支撑业务开发实时和批处理程序。
结合示意图,我们由下而上进行介绍。
Runtime层:
Flink程序的最底层入口。提供基础的核心接口完成流、状态、事件、时间等复杂操作,功能灵活但使用成本较高,一般面向源码研发人员。DataStream/Dataset API层:
这一层主要面向开发者。基于Runtime层抽象为两类API,其中DataStream API处理实时流程序;Dataset API处理批数据程序。Table API:
统一DataStream/DataSet API,抽象成带有Schema信息的表结构API。通过Table操作和注册表完成数据计算,支持与DataStream/Dataset相互转换。SQL:
面向数据分析和开发人员,抽象为SQL操作,降低开发门槛和平台化。
2)Flink计算模型
Flink的计算模型和Spark的模型有些类似。包含输入端(source)、转换(Transform)、输出端(sink)。
source端
:Flink程序的输入端,支持多个数据源对接Transformation
:Flink程序的转换过程,实现DataStream/Dataset的计算和转换sink端
: Flink的输出端,支持内部和外部输出源
Flink 工作原理
Flink底层执行分为客户端
(Client)、Job管理器
(JobManager)、任务执行器
(TaskManager)三种角色组件。其中Client负责Job提交;JobManager负责协调Job执行和Task任务分配;TaskManager负责Task任务执行。
Flink常见执行流程如下(调度器不同会有所区别):
- 1)用户提交流程序Application。
- 2)Flink
解析StreamGraph
。Optimizer
和Builder模块解析程序代码,生成初始StreamGraph
并提交至Client
。 - 3)Client
生成JobGraph
。上述StreamGraph由一系列operator chain构成,在client中会被转换为JobGraph
,即优化多个chain为一个节点,最终提交到JobManager
。 - 4)JobManager
调度Job
。JobManager和Client的ActorSystem
保持通信,并生成ExecutionGraph
(并行化JobGraph)。随后Schduler和Coordinator模块协调并调度Jobz执行。 - 5)TaskManager
部署Task
。TaskManager
和JobManager
的ActorSystem
保持通信,接受job调度计划
并在内部划分TaskSlot
部署执行Task任务
。 - 6)Task
执行
。Task执行期间,JobManager、TaskManager和Client之间保持通信,回传任务状态
和心跳信息
,监控任务执行。
公司怎么提交Flink实时任务的?
顾名思义,这里涉及Flink的部署模式内容。一般Flink部署模式除了Standalone之外,最常见的为Flink on Yarn和Flink on K8s模式,其中Flink on Yarn模式在企业中应用最广。
Flink on Yarn模式细分由可以分为Flink session、Flink per-job和Flink application模式
1)Flink session模式
Flink Session模式会首先启动一个集群
,按照配置约定,集群中包含一定数量的JobManager
和TaskManager
。后面所有提交的Flink Job均共享该集群内的JobManager和TaskManager,即所有的 Flink Job 竞争相同资源。
这样做的好处是节省作业提交资源开销(集群已存在),减少资源和线程切换工作。但是所有作业共享一个JobManager,导致JobManager
压力激增,同时一旦某Job发生故障时会影响到其他作业(中断或重启)。一般仅适用于短周期
、小容量
作业。
Flink-session模式的作业提交流程:
- (1)整体流程分为两部分:yarn-session 集群启动、Job提交。
- (2)
yarn-session集群启动
。请求YarnRM
启动JobManager
,随后JobManager内部启动Dispatcher
和Flink-yarnRM
进程,等待后续Job提交
。 - (3)
Client
提交Job
。Client
连接Dispatcher
开始提交Job,包含jars
和解析过的JobGraph
拓扑数据结构。 - (4)
Dispatcher
启动JobMaster
,JobMaster
向Yarn RM请求slots资源
。 - (5)Flink-Yarn RM 向 Yarn RM 请求
Container
资源,准备启动TaskManager
。 - (6)Yarn启动
TaskManager进程
。TaskManage
r同时向Flink RM反向注册(自身可用的slots槽数) - (7)
TaskManager
为新的作业提供slots
,与JobMaster
通信。 - (8)
JobMaster
将执行的任务分发
给TaskManager
,开始部署执行任务
2)Flink Per-job模式
Flink Per-job模式为每个提交的作业启动集群,各集群间相互独立,并在各自作业完成后销毁,最大限度保障资源隔离。每个Job均衡分发
自身的JobManager,单独进行job的调度和执行。
虽然该模式提供了资源隔离,但是每个job均维护一个集群,启动、销毁以及资源请求消耗时间长,因此比较适用于长时间的任务执行(批处理任务)。
Per-job模式在Flink 1.15中弃用,目前推荐使用applicaiton模式。
Flink 的容错机制(checkpoint)
Checkpoint机制是Flink可靠性的基石,可以保证Flink集群在某个算子因为某些原因(如 异常退出)出现故障时, 能够将整个应用流图的状态恢复到故障之前的某一状态,保证应用流图状态的一致性。Flink的Checkpoint机制原理来自“Chandy-Lamport algorithm”算法。
每个需要Checkpoint的应用在启动时,Flink的JobManager为其创建一个 CheckpointCoordinator(检查点协调器),CheckpointCoordinator全权负责本应用的快照制作。
CheckpointCoordinator(检查点协调器),CheckpointCoordinator全权负责本应用的快照制作。
- CheckpointCoordinator(检查点协调器) 周期性的向该流应用的所有source算子发送 barrier(屏障)。
- 当某个source算子收到一个barrier时,便暂停数据处理过程,然后将自己的当前状态制作成快照,并保存到指定的持久化存储中,最后向CheckpointCoordinator报告自己快照制作情况,同时向自身所有下游算子广播该barrier,恢复数据处理
- 下游算子收到barrier之后,会暂停自己的数据处理过程,然后将自身的相关状态制作成快照,并保存到指定的持久化存储中,最后向CheckpointCoordinator报告自身快照情况,同时向自身所有下游算子广播该barrier,恢复数据处理。
- 每个算子按照步骤3不断制作快照并向下游广播,直到最后barrier传递到sink算子,快照制作完成。
- 当CheckpointCoordinator收到所有算子的报告之后,认为该周期的快照制作成功; 否则,如果在规定的时间内没有收到所有算子的报告,则认为本周期快照制作失败。
Flink Checkpoint与 Spark 的相比,Flink 有什么区别或优势吗
Spark Streaming 的 Checkpoint 仅仅是针对 Driver 的故障恢复做了数据和元数据的 Checkpoint。而 Flink 的 Checkpoint 机制要复杂了很多,它采用的是轻量级的分布式快照,实现了每个算子的快照,及流动中的数据的快照。
-
Event Time:是事件创建的时间。它通常由事件中的时间戳描述,例如采集的日志数据中,每一条日志都会记录自己的生成时间,Flink通过时间戳分配器访问事件时间戳。
-
Ingestion Time:是数据进入Flink的时间。
-
Processing Time:是每一个执行基于时间操作的算子的本地系统时间,与机器相关,默认的时间属性就是Processing Time。
例如,一条日志进入Flink的时间为2021-01-22 10:00:00.123
,到达Window的系统时间为2021-01-22 10:00:01.234
,日志的内容如下:
2021-01-06 18:37:15.624 INFO Fail over to rm2
对于业务来说,要统计1min内的故障日志个数,哪个时间是最有意义的?—— eventTime,因为我们要根据日志的生成时间进行统计。
对于迟到数据是怎么处理的
Flink中 WaterMark 和 Window 机制解决了流式数据的乱序问题,对于因为延迟而顺序有误的数据,可以根据eventTime进行业务处理,对于延迟的数据Flink也有自己的解决办法,主要的办法是给定一个允许延迟的时间,在该时间范围内仍可以接受处理延迟数据:
-
设置允许延迟的时间是通过allowedLateness(lateness: Time)设置
-
保存延迟数据则是通过sideOutputLateData(outputTag: OutputTag[T])保存
-
获取延迟数据是通过DataStream.getSideOutput(tag: OutputTag[X])获取
Flink 资源管理中 Task Slot 的概念
在Flink中每个TaskManager是一个JVM的进程, 可以在不同的线程中执行一个或多个子任务。 为了控制一个worker能接收多少个task。worker通过task slot(任务槽)来进行控制(一个worker至少有一个task slot)。
Flink的重启策略
Flink支持不同的重启策略,这些重启策略控制着job失败后如何重启:
- 固定延迟重启策略
固定延迟重启策略会尝试一个给定的次数来重启Job,如果超过了最大的重启次数,Job最终将失败。在连续的两次重启尝试之间,重启策略会 等待一个固定的时间。
- 失败率重启策略
失败率重启策略在Job失败后会重启,但是超过失败率后,Job会最终被认定失败。在两个连续的重启尝试之间,重启策略会等待一个固定的时间。
- 无重启策略
Job直接失败,不会尝试进行重启。
Flink 是如何保证 Exactly-once 语义的
Flink通过实现两阶段提交和状态保存来实现端到端的一致性语义。分为以下几个步骤:
开始事务(beginTransaction)创建一个临时文件夹,来写把数据写入到这个文件夹里面
预提交(preCommit)将内存中缓存的数据写入文件并关闭
正式提交(commit)将之前写完的临时文件放入目标目录下。这代表着最终的数据会有一些延迟
丢弃(abort)丢弃临时文件
若失败发生在预提交成功后,正式提交前。可以根据状态来提交预提交的数据,也可删除预提交的数据。