1,简单介绍一下 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及多种图计算算法实现。
2,Flink跟Spark Streaming的区别
这个问题是一个非常宏观的问题,因为两个框架的不同点非常之多。但是在面试时有非常重要的一点一定要回答出来:Flink 是标准的实时处理引擎,基于事件驱动。而 Spark Streaming 是微批(Micro-Batch)的模型。
下面我们就分几个方面介绍两个框架的主要区别:
- 架构模型Spark Streaming 在运行时的主要角色包括:Master、Worker、Driver、Executor,Flink 在运行时主要包含:Jobmanager、Taskmanager和Slot。
- 任务调度Spark Streaming 连续不断的生成微小的数据批次,构建有向无环图DAG,Spark Streaming 会依次创建 DStreamGraph、JobGenerator、JobScheduler。Flink 根据用户提交的代码生成 StreamGraph,经过优化生成 JobGraph,然后提交给 JobManager进行处理,JobManager 会根据 JobGraph 生成 ExecutionGraph,ExecutionGraph 是 Flink 调度最核心的数据结构,JobManager 根据 ExecutionGraph 对 Job 进行调度。
- 时间机制Spark Streaming 支持的时间机制有限,只支持处理时间。 Flink 支持了流处理程序在时间上的三个定义:处理时间、事件时间、注入时间。同时也支持 watermark 机制来处理滞后数据。
- 容错机制对于 Spark Streaming 任务,我们可以设置 checkpoint,然后假如发生故障并重启,我们可以从上次 checkpoint 之处恢复,但是这个行为只能使得数据不丢失,可能会重复处理,不能做到恰好一次处理语义。Flink 则使用两阶段提交协议来解决这个问题。
3,作业提交有可能会失败,失败后重新运⾏时,如何保证数据的⼀致性?
Flink 基于 Chandy-Lamport 算法,会把分布式的每⼀个节点的状态保存到分布式⽂件系统⾥⾯作为 Checkpoint(检查点),过程⼤致如下。⾸先,从数据源端开始注⼊ Checkpoint Barrier,它是⼀种⽐较特殊的消息。
然后,它会跟普通的事件⼀样随着数据流去流动,当 Barrier 到达算⼦之后,这个算⼦会把它当前的本地状态进⾏快照保存,当 Barrier 流动到 Sink,所有的状态都保存完整了之后,它就形成⼀个全局的快照。
这样当作业失败之后,就可以通过远程⽂件系统⾥⾯保存的 Checkpoint 来进⾏回滚:先把 Source 回滚到 Checkpoint 记录的offset,然后把有状态节点当时的状态回滚到对应的时间点,进⾏重新计算。这样既可以不⽤从头开始计算,⼜能保证数据语义的⼀致性。
4,Flink集群有哪些角色?
Flink程序在运行时主要有TaskManager,JobManager,Client三种角色。
- JobManager扮演着集群中的管理者Master的角色,它是整个集群的协调者,负责接收Flink Job,协调检查点,Failover 故障恢复等,同时管理Flink集群中从节点TaskManager。
- TaskManager是实际负责执行计算的Worker,在其上执行Flink Job的一组Task,每个TaskManager负责管理其所在节点上的资源信息,如内存、磁盘、网络,在启动的时候将资源的状态向JobManager汇报。
- Client是Flink程序提交的客户端,当用户提交一个Flink程序时,会首先创建一个Client,该Client首先会对用户提交的Flink程序进行预处理,并提交到Flink集群中处理,所以Client需要从用户提交的Flink程序配置中获取JobManager的地址,并建立到JobManager的连接,将Flink Job提交给JobManager。
5,Flink 的核⼼概念有哪些?
Flink 的核⼼概念主要有四个:Event Streams、State、Time 和 Snapshots。
- Event Streams:即事件流,事件流可以是实时的也可以是历史的。Flink 是基于流的,但它不⽌能处理流,也能处理批,⽽流和批的输⼊都是事件流,差别在于实时与批量。
- State:Flink 擅长处理有状态的计算。通常的复杂业务逻辑都是有状态的,它不仅要处理单⼀的事件,⽽且需要记录⼀系列历史的信息,然后进⾏计算或者判断。
- Time:最主要处理的问题是数据乱序的时候,⼀致性如何保证。
- Snapshots:实现了数据的快照、故障的恢复,保证数据⼀致性和作业的升级迁移等。
6,简单介绍下Flink的三种时间语义
Flink的三种时间语义具体包括Event Time、Ingestion Time和Processing Time。
- Event Time:是事件创建的时间。它通常由事件中的时间戳描述,例如采集的日志数据中,每一条日志都会记录自己的生成时间,Flink通过时间戳分配器访问事件时间戳。
- Ingestion Time:是数据进入Flink的时间。
- Processing Time:是每一个执行基于时间操作的算子的本地系统时间,与机器相关,默认的时间属性就是Processing Time。
7,简单描述下Flink状态机制
Flink在做计算的过程中经常需要存储中间状态,来避免数据丢失和状态恢复。选择的状态存储策略不同,会影响状态持久化如何和 checkpoint 交互。
Flink提供了三种状态存储方式:MemoryStateBackend、FsStateBackend、RocksDBStateBackend。
- memoryStateBackend:这种形式状态存储在堆内存中,状态过大可能导致oom问题,checkpoint时快照到jobmanager内存中。
- FsStateBackend:状态保存在taskmanager内存中,与memoryStateBackend不同的是,checkpoint会把state快照到外部文件系统中,相对memoryStateBackend可用性更高。
- RocksDBStateBackend:一种类似于hbase的kv存储本地数据库,依赖于lsm实现,可以将数据保存到本地磁盘上,读写状态时会涉及到序列化反序列化操作,与内存相比,性能会偏低些。但其可以保存比较大的状态,受限于磁盘大小,但其key value依赖于byte数组,大小受byte[]限制。在一些与外部系统交互的场景可以适当的使用rocksdb减少依赖外部系统。同时rocksdb后端支持增量checkpoint。
8,Flink中watermark机制
watermark是⼀种衡量Event Time进展的机制,它是数据本⾝的⼀个隐藏属性。通常基于Event Time的数据,⾃⾝都包含⼀个timestamp.watermark是⽤于处理乱序事件的,⽽正确的处理乱序事件,通常⽤watermark机制结合window来实现。
流处理从事件产⽣,到流经source,再到operator,中间是有⼀个过程和时间的。虽然⼤部分情况下,流到operator的数据都是按照事件产⽣的时间顺序来的,但是也不排除由于⽹络、背压等原因,导致乱序的产⽣(out-of-order或者说late element)。
但是对于late element,我们⼜不能⽆限期的等下去,必须要有个机制来保证⼀个特定的时间后,必须触发window去进⾏计算了。这个特别的机制,就是watermark。
9,什么是Flink的全局快照,为什么需要全局快照?
全局快照⾸先是⼀个分布式应⽤,它有多个进程分布在多个服务器上;其次,它在应⽤内部有⾃⼰的处理逻辑和状态;第三,应⽤间是可以互相通信的;第四,在这种分布式的应⽤,有内部状态,硬件可以通信的情况下,某⼀时刻的全局状态,就叫做全局的快照。
那为什么需要全局快照呢,主要有以下两点:
- 第⼀,⽤它来做检查点,可以定期对全局状态做备份,当应⽤程序故障时,就可以拿来恢复;
- 第⼆,做死锁检测,进⾏快照后当前的程序继续运⾏,然后可以对快照进⾏分 析,看应⽤程序是不是存在死锁状态,如果是就可以进⾏相应的处理。
10,Flink分布式快照的工作原理
Flink的容错机制的核心部分是制作分布式数据流和操作算子状态的一致性快照。 这些快照充当一致性checkpoint,系统可以在发生故障时回滚。 Flink用于制作这些快照的机制在“分布式数据流的轻量级异步快照”中进行了描述。 它受到分布式快照的标准Chandy-Lamport算法的启发,专门针对Flink的执行模型而定制。
barriers在数据流源处被注入并行数据流中。快照n的barriers被插入的位置(我们称之为Sn)是快照所包含的数据在数据源中最大位置。
例如,在Apache Kafka中,此位置将是分区中最后一条记录的偏移量。 将该位置Sn报告给checkpoint协调器(Flink的JobManager)。
然后barriers向下游流动。当一个中间操作算子从其所有输入流中收到快照n的barriers时,它会为快照n发出barriers进入其所有输出流中。
一旦sink操作算子(流式DAG的末端)从其所有输入流接收到barriers n,它就向checkpoint协调器确认快照n完成。
在所有sink确认快照后,意味快照着已完成。一旦完成快照n,job将永远不再向数据源请求Sn之前的记录,因为此时这些记录(及其后续记录)将已经通过整个数据流拓扑,也即是已经被处理结束。
11,什么是Flink的CEP机制
CEP全称为Complex Event Processing,复杂事件处理。Flink CEP是在 Flink 中实现的复杂事件处理(CEP)库。CEP 允许在无休止的事件流中检测事件模式,让我们有机会掌握数据中重要的部分。一个或多个由简单事件构成的事件流通过一定的规则匹配,然后输出用户想得到的数据 —— 满足规则的复杂事件。
12,Flink CEP 编程中当状态没有到达预期数据保存在哪里?
在流式处理中,CEP 当然是要支持 EventTime 的,那么相对应的也要支持数据的迟到现象,也就是watermark的处理逻辑。CEP对未匹配成功的事件序列的处理,和迟到数据是类似的。在 Flink CEP的处理逻辑中,状态没有满足的和迟到的数据,都会存储在一个Map数据结构中,也就是说,如果我们限定判断事件序列的时长为5分钟,那么内存中就会存储5分钟的数据,这在我看来,也是对内存的极大损伤之一。
13,Flink中的窗口
Flink 是一种流式计算引擎,主要是来处理无界数据流的,数据源源不断、无穷无尽。想 要更加方便高效地处理无界流,一种方式就是将无限数据切割成有限的“数据块”进行处理,这 就是所谓的“窗口”(Window)。 在 Flink 中, 窗口就是用来处理无界流的核心。我们很容易把窗口想象成一个固定位置的 “框”,数据源源不断地流过来,到某个时间点窗口该关闭了,就停止收集数据、触发计算并输 出结果。例如,我们定义一个时间窗口,每 10 秒统计一次数据,那么就相当于把窗口放在那 里,从 0 秒开始收集数据;到 10 秒时,处理当前窗口内所有数据,输出一个结果,然后清空 窗口继续收集数据;到 20 秒时,再对窗口内所有数据进行计算处理,输出结果;依次类推。
Flink 支持两种划分窗口的方式,即时间方式和计数方式。如果根据时间划分窗口,那么它就是一个time-window 如果根据数据划分窗口,那么它就是一个count-window。flink支持窗口的两个重要属性(size和interval)如果size=interval,那么就会形成tumbling-window(无重叠数据) 如果size>interval,那么就会形成sliding-window(有重叠数据) 如果size< interval, 那么这种窗口将会丢失数据。比如每5秒钟,统计过去3秒的通过路口汽车的数据,将会漏掉2秒钟的数据。通过组合可以得出四种基本窗口:滚动窗口(Tumbling Window)、 滑动窗口(Sliding Window)、会话窗口(Session Window),以及全局窗口(Global Window)。
参考链接:Flink中的窗口
14,Flink的API可分为哪⼏层?
Flink的API可分为三层:
- SQL或者Table API
- DataStream API
- ProcessFunction
其中,SQL & Table API 同时适⽤于批处理和流处理,这意味着你可以对有界数据流和⽆界数据流以相同的语义进⾏查询,并产⽣相同的结果。除了基本查询外, 它还⽀持⾃定义的标量函数,聚合函数以及表值函数,可以满⾜多样化的查询需求。
DataStream & DataSet API 是 Flink 数据处理的核⼼ API,⽀持使⽤ Java 语⾔或 Scala 语⾔进⾏调⽤,提供了数据读取,数据转换和数据输出等⼀系列常⽤操作的封装。
Stateful Stream Processing 是最低级别的抽象,它通过 Process Function 函数内嵌到 DataStream API 中。下图是常见的一些Process。
15,Flink状态容错
在我们的Flink程序运行时,或许会发生各种各样的错误,导致程序中断,那我们在程序重启时需要找到一个状态并且从这个状态(可以称之为快照)进行恢复,使得程序可以从这个状态重新运行,该机制称之为Checkpoint。
我们的Flink程序很多时候都是7*24小时不间断的运行,需要不间断的过程中源源不断的产生快照(Global consistent snapshot,全局一致性快照)。
Checkpoint是由JobManager触发,假设我们现在需要产生Checkpoint Barrier N,此次Checkpoint一旦被触发,首先会在我们的数据源安插Checkpoint Barrier N,如上图所示,CheckPoint Barrier N前面的数据和事件(红色的圆圈部分)都由Checkpoint Barrier N负责,而N后面的数据和事件(色圆圈部分)则不属于Checkpoint Barrier N的管辖范围。
数据源收到Checkpoint Barrier N时,会先保存自己的状态(假如如果是kafka,那么就是kafka partition的offset),并填入全局一致性快照表格中,当Checkpoint Barrier N流经下游的算子时,算子会暂停数据处理,立即执行Checkpoint形成快照(执行完成以后恢复数据处理),当所有的算子及数据源快照形成完毕以后,我们则认为此次全局一致性快照制作成功,否则制作失败。
16,Flink的状态是如何维护
Flink状态维护指的就是我们维护一组状态值,比如我们需要统计1天的我们页面部分模块的点击PV和UV,当这些状态值非常大时并且开启checkpoint机制时,这些状态则会被持久化到存储中以便恢复,目前状态的存储后端主要有以下三种:MemoryStateBackend、FsStateBackend和RocksDBStateBackend。
- MemoryStateBackend:虚拟机内存,适合状态量不大的应用,内存直接读取写入,本地开发使用。
- FsStateBackend:文件系统,目前可以支持hdfs、oss等,需要从外部存储进行序列化和反序列化进行读取,适用于处理大状态、长窗口的处理任务。
- RocksDBStateBackend:本地数据库,暂存在本地磁盘,当checkpoint进行时依然会存储到文件系统中,该存储后端适用于大状态,长窗口的处理任务,并且支持增量checkpoint。
17,Flink 的运⾏必须依赖 Hadoop组件吗
Flink可以完全独⽴于Hadoop,在不依赖Hadoop组件下运⾏。但是做为⼤数据的基础设施,Hadoop体系是任何⼤数据框架都绕不过去的。Flink可以集成众多Hadooop 组件,例如Yarn、Hbase、HDFS等等。例如,Flink可以和Yarn集成做资源调度,也可以读写HDFS,或者利⽤HDFS做检查点。
18,简述下Flink 资源管理中 Task Slot 的概念
TaskManager是一个jvm进程,,并会以独立的线程来执行一个task或多个subtask。为了控制一个 TaskManager 能接受多少个 task,Flink 提出了 Task Slot 的概念。
Flink 中的计算资源通过 Task Slot 来定义。每个 task slot 代表了 TaskManager 的一个固定大小的资源子集。例如,一个拥有3个slot的 TaskManager,会将其管理的内存平均分成三分分给各个 slot。将资源 slot 化意味着来自不同job的task不会为了内存而竞争,而是每个task都拥有一定数量的内存储备。需要注意的是,这里不会涉及到CPU的隔离,slot目前仅仅用来隔离task的内存。
通过调整 task slot 的数量,用户可以定义task之间是如何相互隔离的。每个 TaskManager 有一个slot,也就意味着每个task运行在独立的 JVM 中。每个 TaskManager 有多个slot的话,也就是说多个task运行在同一个JVM中。而在同一个JVM进程中的task,可以共享TCP连接(基于多路复用)和心跳消息,可以减少数据的网络传输。也能共享一些数据结构,一定程度上减少了每个task的消耗。
简单的说,TaskManager会将⾃⼰节点上管理的资源分为不同的Slot:固定⼤⼩的资源⼦集。这样就避免了不同Job的Task互相竞争内存资源,但是需要主要的是,Slot只会做内存的隔离。没有做CPU的隔离。
19,Flink的重启策略都有哪些
Flink的重启策略主要有几下四种:
- 固定延迟重启策略(Fixed Delay Restart Strategy)
- 故障率重启策略(Failure Rate Restart Strategy)
- 没有重启策略(No Restart Strategy)
- Fallback重启策略(Fallback Restart Strategy)
默认重启策略是通过Flink的配置文件设置的flink-conf.yaml。定义策略的配置key为: restart-strategy。如果未启用检查点,则使用“无重启”策略。如果激活了检查点但未配置重启策略,则使用“固定延迟策略”:restart-strategy.fixed-delay.attempts: Integer.MAX_VALUE尝试重启。
使用群集定义的重新启动策略。这对于启用检查点的流式传输程序很有帮助。默认情况下,如果没有定义其他重启策略,则选择固定延迟重启策略。
20,简述Flink的内存模型
参考链接:Flink内存模型
21,什么是数据倾斜问题
简单来说数据倾斜就是数据的key 的分化严重不均,造成一部分数据很多,一部分数据很少的局面。数据倾斜表现为以下几种场景:
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、聚合。
22,Flink-On-Yarn常见的提交模式有哪些,有什么优缺点?
Flink-On-Yarn常见的提交模式有两种,分别是yarn-session和per-job模式。
- yarn-session模式:这种⽅式需要先启动集群,然后在提交作业,接着会向yarn申请⼀块空间后,资源永远保持不变。如果资源满了,下⼀个就任务就⽆法提交,只能等到yarn中其中⼀个作业完成后,释放了资源,那下⼀个作业才会正常提交,这种⽅式资源被限制在session中,不能超过,⽐较适合特定的运⾏环境或测试环境。
- per-job模式:这种⽅式直接在yarn上提交任务运⾏Flink作业,这种⽅式的好处是⼀个任务会对应⼀个job,即每提交⼀个作业会根据⾃⾝的情况,向yarn中申请资源,直到作业执⾏完成,并不会影响下⼀个作业的正常运⾏,除⾮是yarn上⾯没有任何资源的情况下。⼀般⽣产环境是采⽤此⽅式运⾏。这种⽅式需要保证集群资源⾜够。
23,Flink如何解决任务延迟⾼
在Flink的后台任务管理中,我们可以看到Flink的那个算⼦和task出现了反压。最主要的⼿段是资源调优和算⼦调优,即对作业中的Operator的并发数(parallelism)、CPU(core)、堆内存(heap_memory)等参数进行调优。作业参数调优包括:并行度的设置,State的设置,checkpoint的设置。
24,什么是Flink Operator Chains
为了更⾼效地分布式执⾏,Flink会尽可能地将operator的subtask链接(chain)在⼀起形成task。每个task在⼀个线程中执⾏。将operators链接成task是⾮常有效的优化:它能减少线程之间的切换,减少消息的序列化/反序列化,减少数据在缓冲区的交换,减少了延迟的同时提⾼整体的吞吐量。这就是我们所说的算⼦链。其实就是尽量把操作逻辑放⼊到同⼀个subtask⾥⾯也就是⼀个槽TaskSolt。
25,Flink 程序在⾯对数据⾼峰期时如何处理?
使⽤⼤容量的 Kafka 把数据先放到消息队列⾥⾯作为数据源,再使⽤Flink 进⾏消费,不过这样会影响到⼀点实时性。