1.什么是Apache Flink(为什么使用 Flink 替代 Spark?)
Apache Flink 是一个开源的基于流的有状态计算框架。它是分布式地执行的,具备低延迟、高吞吐的优秀性能,并且非常擅长处理有状态的复杂计算逻辑场景。
2.Flink 的核心概念
Flink 的核心概念主要有四个:Event Streams、State、Time 和 Snapshots。
- Event Streams:即事件流,事件流可以是实时的也可以是历史的。Flink 是基于流的,但它不止能处理流,也能处理批,而流和批的输入都是事件流,差别在于实时与批量。
- State:Flink 擅长处理有状态的计算。通常的复杂业务逻辑都是有状态的,它不仅要处理单一的事件,而且需要记录一系列历史的信息,然后进行计算或者判断。
- Time:最主要处理的问题是数据乱序的时候,一致性如何保证。
- Snapshots:实现了数据的快照、故障的恢复,保证数据一致性和作业的升级迁移等。
3.作业在很多情况下有可能会失败。失败之后重新去运行时,我们如何保证数据的一致性?
Flink 基于 Chandy-Lamport 算法,会把分布式的每一个节点的状态保存到分布式文件系统里面作为 Checkpoint(检查点),过程大致如下。首先,从数据源端开始注入 Checkpoint Barrier,它是一种比较特殊的消息。
然后它会跟普通的事件一样随着数据流去流动,当 Barrier 到达算子之后,这个算子会把它当前的本地状态进行快照保存,当 Barrier 流动到 Sink,所有的状态都保存完整了之后,它就形成一个全局的快照。
这样当作业失败之后,就可以通过远程文件系统里面保存的 Checkpoint 来进行回滚:先把 Source 回滚到 Checkpoint 记录的 offset,然后把有状态节点当时的状态回滚到对应的时间点,进行重新计算。这样既可以不用从头开始计算,又能保证数据语义的一致性。
4.Flink的时间语义
- Event Time:事件创建的时间
- Ingestion Time:数据进入Flink的时间
- Processing Time:执行操作算子的本地系统时间,与机器相关
5.Flink的API可分为哪几层?
- SQL & Table API 同时适用于批处理和流处理,这意味着你可以对有界数据流和无界数据流以相同的语义进行查询,并产生相同的结果。除了基本查询外, 它还支持自定义的标量函数,聚合函数以及表值函数,可以满足多样化的查询需求。
- DataStream & DataSet API 是 Flink 数据处理的核心 API,支持使用 Java 语言或 Scala 语言进行调用,提供了数据读取,数据转换和数据输出等一系列常用操作的封装。
- Stateful Stream Processing 是最低级别的抽象,它通过 Process Function 函数内嵌到 DataStream API 中。 Process Function 是 Flink 提供的最底层 API,具有最大的灵活性,允许开发者对于时间和状态进行细粒度的控制。
6.Flink 运行时组件
1) 作业管理器(JobManager)
- 控制一个应用程序执行的主进程,也就是说,每个应用程序都会被一个不同的Jobmanager所控制执行
- Jobmanager会先接收到要执行的应用程序,这个应用程序会包括:作业图( Job Graph)、逻辑数据流图( ogical dataflow graph)和打包了所有的类、库和其它资源的JAR包。
- Jobmanager会把Jobgraph转换成一个物理层面的数据流图,这个图被叫做“执行图”(Executiongraph),包含了所有可以并发执行的任务。Job Manager会向资源管理器(Resourcemanager)请求执行任务必要的资源,也就是任务管理器(Taskmanager)上的插槽slot。一旦它获取到了足够的资源,就会将执行图分发到真正运行它们的 Taskmanager上。而在运行过程中Jobmanagera会负责所有需要中央协调的操作,比如说检查点(checkpoints)的协调。
2) 任务管理器(TaskManager)
- Flink中的工作进程。通常在 Flink中会有多个Taskmanager运行,每个Taskmanager都包含了一定数量的插槽(slots)。插槽的数量限制了Taskmanager能够执行的任务数量。
- 启动之后,Taskmanager会向资源管理器注册它的插槽;收到资源管理器的指令后, Taskmanager就会将一个或者多个插槽提供给Jobmanager调用。Jobmanager就可以向插槽分配任务(tasks)来执行了。
- 在执行过程中,一个Taskmanager可以跟其它运行同一应用程序的Taskmanager交换数据。
3) 资源管理器(ResourceManager)
- 主要负责管理任务管理器(TaskManager)的插槽(slot)Taskmanger插槽是Flink中定义的处理资源单元。
- Flink为不同的环境和资源管理工具提供了不同资源管理器,比如YARN、K8s,以及 standalone部署。
- 当Jobmanager申请插槽资源时,Resourcemanager会将有空闲插槽的Taskmanager分配给Jobmanager。如果 Resourcemanager没有足够的插槽来满足 Jobmanager的请求,它还可以向资源提供平台发起会话,以提供启动 Taskmanager进程的容器。
4) 分发器(Dispatcher)
- 可以跨作业运行,它为应用提交提供了REST接口。
- 当一个应用被提交执行时,分发器就会启动并将应用移交给Jobmanage。
- Dispatcher他会启动一个WebUi,用来方便地展示和监控作业执行的信息。
7.Flink任务提交流程
8.任务提交流程(YARN)
- Flink任务提交后,Client向HDFS上传Flink的Jar包和配置
- 随后向Yarn ResourceManager提交任务,ResourceManager分配Container资源并通知对应的NodeManager启动
- ApplicationMaster,ApplicationMaster启动后加载Flink的Jar包和配置构建环境
- 然后启动JobManager,之后ApplicationMaster向ResourceManager申请资源启动 TaskManager
- ResourceManager分配Container资源后,由ApplicationMaster通知资源所在节点的NodeManager启动TaskManager
- NodeManager加载Flink的Jar包和配置构建环境并启动TaskManager
- TaskManager启动后向JobManager发送心跳包,并等待JobManager向其分配任务。
9.Flink的执行图
Flink中的执行图可以分成四层: Streamgraph -> Jobgraph -> Executiongraph -> 物理执行图
- Streamgraph:是根据用户通过 Stream API编写的代码生成的最初的图。用来表示程序的拓扑结构。
- Jobgraph:Streamgraph经过优化后生成了 Jobgraph,提交给 Jobmanager的数据结构。主要的优化为,将多个符合条件的节点 chain在一起作为一个节点。
- Execution Graph:Jobmanager根据 Jobgraph生成,是 Jobgraph的并行化版本,是调度层最核心的数据结构。
- 物理执行图:Jobmanager根据 Executiongraph对Job进行调度后,在各个Taskmanager上部署Task后形成的“图”,并不是一个具体的数据结构。
10.Flink的分区策略
11.Flink 的状态分为哪两类
作为对状态支持比较好的系统,Flink内部提供了可以使用的很多种可选的状态原语。从大的角度看, 所有状态原语可以分为KeyedState和OperatorState 两类。
12.KeyedState都有哪几类
Keyed State 可以进一步划分为下面的 5 类,它们分别是
- 比较常用的:ValueState、ListState、MapState
- 不太常用的:ReducingState 和 AggregationState
13.Flink中watermark的概念
watermark是一种衡量Event Time进展的机制,它是数据本身的一个隐藏属性。通常基于Event Time的数据,自身都包含一个timestamp.watermark是用于处理乱序事件的,而正确的处理乱序事件,通常用watermark机制结合window来实现。
流处理从事件产生,到流经source,再到operator,中间是有一个过程和时间的。虽然大部分情况下,流到operator的数据都是按照事件产生的时间顺序来的,但是也不排除由于网络、背压等原因,导致乱序的产生(out-of-order或者说late element)。
但是对于late element,我们又不能无限期的等下去,必须要有个机制来保证一个特定的时间后,必须触发window去进行计算了。这个特别的机制,就是watermark。
14.什么是Flink的全局快照
全局快照首先是一个分布式应用,它有多个进程分布在多个服务器上;其次,它在应用内部有自己的处理逻辑和状态;第三,应用间是可以互相通信的;第四,在这种分布式的应用,有内部状态,硬件可以通信的情况下,某一时刻的全局状态,就叫做全局的快照。
15.为什么需要全局快照
- 第一,用它来做检查点,可以定期对全局状态做备份,当应用程序故障时,就可以拿来恢复;
- 第二,做死锁检测,进行快照后当前的程序继续运行,然后可以对快照进行分 析,看应用程序是不是存在死锁状态,如果是就可以进行相应的处理。
16.Flink的容错机制
- Exactly once,是指每条 event 会且只会对 state 产生一次影响,这里的“一次”并非端到端的严格一次,而是指在 Flink 内部只处理一次,不包括 source和 sink 的处理。
- At least once,是指每条 event 会对 state 产生最少一次影响,也就是存在重复处理的可能。
- At most once,是指每条 event 会对 state 产生最多一次影响,就是状态可能会在出错时丢失。
17.Flink是如何实现End-To-End Exactly-once的?
Flink通过状态和两次提交协议来保证了端到端的exactly-once语义
- Source:支持数据的replay,如Kafka的offset。
- Transformation:借助于checkpoint
- Sink:Checkpoint + 两阶段事务提交
18.解释下两阶段提交?
- 一旦Flink开始做checkpoint操作,就会进入pre-commit “预提交”阶段,同时JobManager的Coordinator会将Barrier注入数据流中。
- 当所有的barrier在算子中成功进行一遍传递(就是Checkpoint完成),并完成快照后,“预提交”阶段完成。
- 等所有的算子完成“预提交”,就会发起一个commit “提交”动作,但是任何一个“预提交” 失败都会导致Flink回滚到最近的checkpoint。
19.两阶段提交API
- beginTransaction:在开启事务之前,我们在目标文件系统的临时目录中创建一个临时文件,后面在处理数据时将数据写入此文件。
- preCommit:在预提交阶段,刷写(flush)文件,然后关闭文件,之后就不能写入到文件了,我们还将为属于下一个检查点的任何后续写入启动新事务。
- commit:在提交阶段,我们将预提交的文件原子性移动到真正的目标目录中,请注意,这回增加输出数据可见性的延迟。
- abort:在中止阶段,我们删除临时文件。
20.Flink 的 checkpoint 存在哪里?
可以是内存,文件系统,或者 RocksDB。
21.海量 key 去重
如果是海量数据的话,Set结构是不现实的,可以考虑使用布隆过滤器来去重。
22.Flink 的 checkpoint 机制对比 spark 有什么不同和优势?
spark streaming 的 checkpoint 仅仅是针对 driver 的故障恢复做了数据和元数据的 checkpoint。而 flink 的 checkpoint 机制 要复杂了很多,它采用的是轻量级的分布式快照,实现了每个算子的快照,及流动中的数据的快照。
23.Flink CEP 编程中当状态没有到达的时候会将数据保存在哪里?
在 Flink CEP 的处理逻辑中,状态没有满足的和迟到的数据,都会存储在一个 Map 数据结构中,也就是说,如果我们限定判断事件序列的时长为 5 分钟,那么内存中就会存储 5 分钟的数据。
24.Flink 程序在面对数据高峰期时如何处理?
使用大容量的 Kafka 把数据先放到消息队列里面作为数据源,再使用Flink 进行消费,不过这样会影响到一点实时性。
25.Flink 的运行必须依赖 Hadoop组件吗?
Flink可以完全独立于Hadoop,在不依赖Hadoop组件下运行。但是做为大数据的基础设施,Hadoop体系是任何大数据框架都绕不过去的。Flink可以集成众多Hadooop 组件,例如Yarn、Hbase、HDFS等等。例如,Flink可以和Yarn集成做资源调度,也可以读写HDFS,或者利用HDFS做检查点。
26.Flink 资源管理中 Task Slot 的概念
在Flink架构角色中我们提到,TaskManager是实际负责执行计算的Worker,TaskManager 是一个 JVM 进程,并会以独立的线程来执行一个task或多个subtask。为了控制一个 TaskManager 能接受多少个 task,Flink 提出了 Task Slot 的概念。
简单的说,TaskManager会将自己节点上管理的资源分为不同的Slot:固定大小的资源子集。这样就避免了不同Job的Task互相竞争内存资源,但是需要主要的是,Slot只会做内存的隔离。没有做CPU的隔离。
27.Flink的重启策略都有哪些?
-
固定延迟重启策略(Fixed Delay Restart Strategy)
-
故障率重启策略(Failure Rate Restart Strategy)
-
没有重启策略(No Restart Strategy)
-
Fallback重启策略(Fallback Restart Strategy)
28.Flink中的广播变量,使用时需要注意什么?
我们知道Flink是并行的,计算过程可能不在一个 Slot 中进行,那么有一种情况即:当我们需要访问同一份数据。那么Flink中的广播变量就是为了解决这种情况。
我们可以把广播变量理解为是一个公共的共享变量,我们可以把一个dataset 数据集广播出去,然后不同的task在节点上都能够获取到,这个数据在每个节点上只会存在一份。
29.Flink的内存模型
30.数据倾斜问题
1.keyBy之前发生数据倾斜
如果keyBy之前就存在数据倾斜,上游算子的某些实例可能处理的数据较多,某些实例可能处理的数据较少,产生该情况可能是因为数据源的数据本身就不均匀,例如由于某些原因Kafka的topic中某些partition的数据量较大,某些partition的数据量较少。对于不存在keyBy的Flink任务也会出现该情况。
这种情况,需要让Flink任务强制进行shuffle。使用shuffle、rebalance、rescale算子即可将数据均匀分配,从而解决数据倾斜的问题。
2.keyBy之后无开窗聚合数据倾斜
map端使用状态先预聚合,达到一定时间或者一定size后再同一输出(localkeyby)。
3.keyBy后的窗口聚合操作存在数据倾斜
因为使用了窗口,变成了有界数据的处理,窗口默认是触发时才会输出一条结果发往下游,所以可以使用两阶段聚合的方式:
第一阶段聚合:key拼接随机数前缀或后缀,进步keyby、开窗、聚合。
第二阶段聚合:去掉随机数前缀或后缀,按照原来的key及windowEnd作keyby、聚合。
31.Flink连接API
- union 多流合并,类型一致
- connect 两条流分别处理,类型可不一致,可共享状态
- join 相当于innerjoin
- coGroup 实现左外连接,第一个流没有join上,也要输出
32.Flink-On-Yarn常见的提交模式有哪些,分别有什么优缺点?
1.yarn-session模式:
这种方式需要先启动集群,然后在提交作业,接着会向yarn申请一块空间后,资源永远保持不变。如果资源满了,下一个就任务就无法提交,只能等到yarn中其中一个作业完成后,释放了资源,那下一个作业才会正常提交,这种方式资源被限制在session中,不能超过,比较适合特定的运行环境或测试环境。
2.per-job模式:
这种方式直接在yarn上提交任务运行Flink作业,这种方式的好处是一个任务会对应一个job,即每提交一个作业会根据自身的情况,向yarn中申请资源,直到作业执行完成,并不会影响下一个作业的正常运行,除非是yarn上面没有任何资源的情况下。一般生产环境是采用此方式运行。这种方式需要保证集群资源足够。
33.Flink如何处理迟到数据
- watermark可以设置延迟时间
- window的allowedLateness方法,可以设置窗口允许处理迟到数据的时间
- window的sideOutputLateData方法,可以将迟到的数据写入侧输出流
34.Flink任务延迟高如何解决
在Flink的后台任务管理中,我们可以看到Flink的那个算子和task出现了反压。最主要的手段是资源调优和算子调优。例如调大并发,增加运行任务的资源。缩短窗口时长。
35.Flink Operator Chains
为了更高效地分布式执行,Flink会尽可能地将operator的subtask链接(chain)在一起形成task。每个task在一个线程中执行。将operators链接成task是非常有效的优化:它能减少线程之间的切换,减少消息的序列化/反序列化,减少数据在缓冲区的交换,减少了延迟的同时提高整体的吞吐量。这就是我们所说的算子链。其实就是尽量把操作逻辑放入到同一个subtask里面也就是一个槽TaskSolt。
36.Flink什么情况下才会把Operator chain在一起形成算子链?
- 上下游并行度一致
- 下游数据没有其他的输入
- 上下游节点都在同一个soltgroup中,默认是一样的,如果不是,单独指定的算子资源,会独占TaskSolt
- 没有keyed操作
- 数据发送策略是forward
- 用户没有禁用chain
37.Flink中应用在tableAPI中的UDF有几种?
- scalar function:针对一条record的一个字段的操作,返回一个字段
- table function:针对一条record的一个字段的操作,返回多个字段
- aggregate function:针对多条记录的一个字段操作,返回一条记录
本文来自博客园,作者:大码王,转载请注明原文链接:https://www.cnblogs.com/huanghanyu/