1、什么是Flink?
Flink项目的理念是:Apache Flink是为分布式、高性能、随时可用以及准确的流处理应用程序打造的开源流处理框架。
Apache Flink是一个框架和分布式处理引擎,用于对无界和有界数据流进行有状态计算。Flink被设计在所有常见的集群环境中运行,以内存执行速度和任意规模来执行计算。
Flink能够提供毫秒级别的延迟,同时保证了数据处理的低延迟、高吞吐和结果的正确性,还提供了丰富的时间类型和窗口计算、Exactly-once(就一次)语义支持,另外还可以进行状态管理,并提供了 CEP(复杂事件处理)的支持。
2、SparkStreaming和Strom的区别?
Storm Flink
状态管理 无状态,需用户自行进行状态管理 有状态
窗口支持 对事件窗口支持较弱,缓存整个窗口的所有数据,窗口结束时一起计算 窗口支持较为完善,自带一些窗口聚合方法,并且会自动管理窗口状态
消息投递 At Most Once/At Least Once At Most Once/At Least Once/Exactly Once
容错方式 ACK机制:对每个消息进行全链路跟踪,失败或超时进行重发 检查点机制:通过分布式一致性快照机制,对数据流和算子状态进行保存;在发生错误时,使系统能够进行回滚
应用现状 在美团点评实时计算业务中已有较为成熟的运用,有管理平台、常用API和相应的文档,大量实时作业基于Storm构建 在美团点评实时计算业务中已有一定应用,但是管理平台、API及文档等仍需进一步完善
3、Flink和SparkStreaming的区别?
这个问题是一个非常宏观的问题,因为两个框架的不同点非常之多,但是在面试时有非常重要的一点一定要回答出来:Flink是标准的实时处理引擎,基于事件驱动;SparkStreaming是微批(Micro-Batch)的模型。
SparkStreaming Flink
架构模型 主要角色包括:Master、Worker、Driver和Executor 主要包括:JobManager、TaskManager和Slot
任务调度 连续不间断的生成微小的数据批次,构建有向无环图DAG,会依次创建DStreamGraph、JobGenerator、JobScheduler 根据用户提交的代码生成StreamGraph,经过优化生成JobGraph,然后提交给JobManager进行处理,JobManager会根据JobGraph生成ExecutionGraph,ExecutionGraph是Flink调度最核心的数据结构,JobManager根据ExecutionGraph对Job进行调度
时间机制 只支持处理时间 支持处理时间、事件时间、注入时间;同时也支持watermark机制来处理滞后数据
容错机制 可以设置checkpoint,假如发生故障并重启,可以从上次checkpoint之处恢复,但是这个行为只能使得数据不丢失,可能会重复处理,不能做到恰好一次处理语义 使用两阶段提交(2PC)协议来解决可能重复处理问题,做到恰好一次处理语义
4、Flink的重要特点?
时间驱动型(Event-driven)
时间驱动型应用是一类具有状态的应用,它从一个或多个事件流提取数据,并根据到来的时间触发计算、状态更新或其他外部动作
流与批的世界观
批处理:有界、持久、大量,非常适合需要访问全套记录才能完成的计算工作,一般用于离线统计
流处理:无界、实时,无需针对整个数据集执行操作,而是对通过系统传输的每个数据项执行操作,一般用于实时统计
分层API
Flink提供的最高层级的抽象是SQL
越顶层越抽象,表达含义越明显,使用越方便
越底层越具体,表达能力越丰富,使用越灵活
5、什么是有界流和无界流?
无界数据流
无界数据流有一个开始但是没有结束,它们不会在生成时终止并提供数据,必须连续处理无界流,也就是说必须再获取后立即处理event;
对于无界数据流是无法等待所有数据都到达,因为输入是无界的,并且再任何时间点都不会完成;
处理无界数据通常要求以特定顺序(例如事件发生的顺序)获取event,以便能够推断结果完整性。
有界数据流
有界数据流有明确定义的开始和结束,可以在执行任何计算之前通过获取所有数据来处理有界流;
处理有界流不需要有序获取,因为可以始终对有界数据集进行排序,有界流的处理也称为批处理。
这种以流为世界观的架构,获得的最大好处就是具有极低的延迟。
6、Flink的其他特点?
支持事件事件(event-time)和处理时间(processing time)
精确一次的状态一致性保证
低延迟,每秒处理数百万个事件,毫秒级延迟
与众多常用存储系统连接
高可用,动态扩展,实现7 * 24小时全天侯运行
7、Flink的组件?
作业管理器(JobManager)
任务管理器(TaskManager)
资源管理器(ResourceManager)
分发器(Dispatcher)
8、JobManager的作用?
控制一个应用程序执行的主进程,也就是说,每个应用程序都会被一个不同的JobManager所控制执行
JobManager会先接收到要执行的应用程序
JobManager会把JobGraph转换成一个物理层面的数据流图,这个图被叫做“执行图”(ExecutionGraph),包含了所有可以并发执行的任务
JobManager会向资源管理器(ResourceManager)请求执行任务必要的资源,也就是任务管理器(TaskManager)上的插槽(slot);一旦它获取到了足够的资源,就会将执行图分发到真正运行它们的TaskManager上;而在运行过程中,JobManager会负责所有需要中央协调的操作,如检查点(checkpoints)的协调
9、JobManager收到的应用程序包含哪些?
作业图(JobGraph)
逻辑数据流图(Logical Dataflow Graph)
打包了所有的类、库和其他资源的JAR包
10、TaskManager的作用?
Flink中的工作进程;通常在Flink中会有多个TaskManager运行,每一个TaskManager都包含了一定数量的插槽(slots)
启动之后,TaskManager会向资源管理器注册它的插槽;收到资源管理器的指令后,TaskManager就会将一个或者多个插槽提供给JobManager调用;JobManager就可以向插槽分配任务(tasks)来执行了
task的数量由TaskManager内包含的slots的总数量决定,slot的总数量也决定了任务执行的并行度
在执行过程中,一个TaskManager可以跟其他运行同一应用程序的TaskManager交换数据
11、TaskManager执行任务的数量由什么来决定的?
插槽的数量限制了TaskManager能够执行的任务数量
12、ResourceManager的作用?
主要负责管理任务管理器(TaskManager)的插槽(slot)
Flink为不同的环境和资源管理工具提供了不同资源管理器,比如YARN、Mesos、K8s以及Standalone部署
当JobManager申请插槽资源时,ResourceManager会将有空闲插槽的TaskManager分配给JobManager;如果ResourceManager没有足够的插槽来满足JobManager的请求,它还可以向资源提供平台发起会话,以提供启动TaskManager进程的容器
另外,ResourceManager还负责终止空闲的TaskManager,释放计算资源
13、Flink的资源单元?
TaskManager插槽是Flink中定义的处理资源单元
14、分发器的作用?
可以跨作业运行,它为应用提交提供了REST接口
当一个应用被提交执行时,分发器就会启动并将应用移交给一个JobManager
Dispatcher也会启动一个Web UI,用来方便地展示和监控作业执行地信息
Dispatcher在架构中可能并不是必需地,这取决于应用提交运行的方式
15、任务提交流程
Flink的各个组件的交互协作
在这里插入图片描述
如果部署的集群环境不同(如YARN、Mesos、K8s以及Standalone等),其中一些步骤可以被省略,或是有些组件会运行在同一个JVM进程中
Flink集群部署到YARN上
在这里插入图片描述
16、Flink的程序由几部分组成?
所有的Flink程序都是由三部分组成的:Source、Transformation和Sink
Source:负责读取数据源
Transformation:利用各种算子进行处理加工
Sink:负责输出
17、Flink的执行图分为几层?
Flink中的执行图可以分成四层:
StreamGraph:根据用户通过Stream API编写的代码生成的最初的图;用来表示程序的拓扑结构
JobGraph:StreamGraph经过优化后生成了JobGraph,提交给JobManager的数据结构;主要的优化为,将多个符合条件的节点链接在一起,这样可以减少数据在节点之间流动所需要的序列化/反序列化/传输消耗
ExecutionGraph:JobManager根据JobGraph生成ExecutionGraph;ExecutionGraph是JobGraph的并行化版本,是调度层最核心的数据结构
物理执行图:JobManager根据ExecutionGraph对Job进行调度后,在各个TaskManager上部署Task后形成的“图”,并不是一个具体的数据结构
18、算子之间数据传输的形式?
One-to-one:类似于Spark中的窄依赖
stream(比如在source和map operator之间)维护着分区以及元素的顺序,那意味着map算子的子任务看到的元素的个数以及顺序跟source算子的子任务生产的元素的个数、顺序相同,map、fliter、flatMap等算子都是one-to-one的对应关系
Redistributing:类似于Spark中的宽依赖
stream(map()跟keyBy/window之间或者keyBy/window跟sink之间)的分区会发生改变;每一个算子的子任务依据所选择的transformation发送数据到不同的目标任务。例如,keyBy()基于hashCode重分区、broadcast和rebalance会随机重新分区,这些算子都会引起redistribute过程,而redistribute过程就类似于Spark中的shuffle过程
19、Flink的任务链?任务链的要求?
Flink采用了一种称为任务链的优化技术,可以在特定条件下减少本地通信的开销;为了满足任务链的要求,必须将两个或多个算子设为相同的并行度,并通过本地转发(local forward)的方式进行连接
相同并行度的one-to-one操作,Flink这样相连的算子连接在一起形成一个task,原来的算子成为u里面的subtask
并行度相同、并且是one-to-one操作,两个条件缺一不可
20、Flink中Split和Select?
在这里插入图片描述
DataStream → SplitStream:根据某些特征把一个DataStream拆分成两个或者多个DataStream
在这里插入图片描述
SplitStream →DataStream:从一个SplitStream中获取一个或者多个DataStream
21、Flink中Union与Connect区别?
Union之前两个流的类型必须是一样;Connect可以不一样,在之后的CoMap中再去调整成为一样的
Union可以操作多个流;Connect只能操作两个流
22、Flink中的rich函数?
“富函数”是DataStream API提供的一个函数类的接口,所有Flink函数类都有其Rich版本
它与常规函数的不同在于,可以获取运行环境的上下文,并拥有一些生命周期方法,所以可以实现更复杂的功能
RichMapFunction
RichFlatMapFunction
RichFilterFunction
…
Rich Functions有一个生命周期的概念,典型的生命周期方法有:
open():初始化方法,当一个算子(例如map或者filter)被调用之前open()会被调用
close():生命周期中的最后一个调用的方法,做一些清理工作
getRuntimeContext():提供了函数的RuntimeContext的一些信息,例如函数执行的并行度,任务的名字,以及state状态
23、Flink的window分为几种?
CountWindow:按照指定的数据条数生成一个Window,与时间无关
TimeWindow:按照时间生成Window
Global Window:全局窗口
24、TimeWindow分为哪几种?
滚动窗口(Tumbling Windows):将数据依据固定的窗口长度对数据进行切片
特点:时间对齐,窗口长度固定,没有重叠
适用场景:适合做 BI 统计等(做每个时间段的聚合计算)
滑动窗口(Sliding Windows):是固定窗口的更广义的一种形式,滑动窗口由固定的窗口长度和滑动间隔组成
特点:时间对齐,窗口长度固定,可以有重叠
适用场景:对最近一个时间段内的统计
会话窗口(Session Windows):由一系列事件组合一个指定时间长度的timeout间隙组成,类似于web应用session,也就是一段时间没有接收到新数据就会生成新的窗口
特点:时间无对齐
25、WindowFunction对数据的计算分为两类?
增量聚合函数(incremental aggregation functions)
每条数据到来就进行计算,保持一个简单的状态
典型的增量聚合函数有ReduceFunction,AggregateFunction
全窗口函数(full window functions)
先把窗口所有数据收集起来,等到计算的时候会遍历所有数据
ProcessWindowFunction就是一个全窗口函数
26、Flink提供了8个ProcessFunction?
ProcessFunction
KeyedProcessFunction
CoProcessFunction
ProcessJoinFunction
BroadcastProcessFunction
KeyedBroadcastProcessFunction
ProcessWindowFunction
ProcessAllWindowFunction
27、Flink的TimerService?
Context和OnTimerContext所持有的TimerService对象拥有以下方法:
currentProcessingTime():Long返回当前处理时间
currentWatermark():Long返回当前watermark的时间戳
registerProcessingTimeTimer(timestamp: Long): Unit:会注册当前key的processing time的定时器;当processing time到达定时时间时,触发timer
registerEventTimeTimer(timestamp: Long): Unit:会注册当前key的event time定时器;当水位线大于等于定时器注册的时间时,触发定时器执行回调函数
deleteProcessingTimeTimer(timestamp: Long): Unit:删除之前注册处理时间定时器;如果没有这个时间戳的定时器,则不执行
deleteEventTimeTimer(timestamp: Long): Unit:删除之前注册的事件时间定时器,如果没有此时间戳的定时器,则不执行
当定时器timer触发时,会执行回调函数onTimer();注意定时器timer只能在keyed streams上面使用
28、Flink中状态的类型?
算子状态(Operator State)
键控状态(Keyed State)
29、Flink为算子状态提供三种基本数据结构?
列表状态(List state)
将状态表示为一组数据的列表
联合列表状态(Union list state)
也将状态表示为数据的列表;它与常规列表状态的区别在于,在发生故障时,或者从保存点(savepoint)启动应用程序时如何恢复
广播状态(Broadcast state)
如果一个算子有多项任务,而它的每项任务状态又都相同,那么这种特殊情况最适合应用广播状态
30、Flink状态一致性的级别?
at-most-once
这其实是没有正确性保障的委婉说法,故障发生之后,计数结果可能丢失
at-least-once
这表示计数结果可能大于正确值,但绝对不会小于正确值;也就是说,计数程序在发生故障后可能多算,但是绝不会少算
exactly-once
这指的是系统保证在发生故障后得到的计数结果与正确值一致
31、什么是端到端的一致性?
目前我们看到的一致性保证都是由流处理器实现的,也就是说都是在 Flink 流处理器内部保证的;而在真实应用中,流处理应用除了流处理器以外还包含了数据源(例如Kafka)和输出到持久化系统
端到端的一致性保证,意味着结果的正确性贯穿了整个流处理应用的始终;每一个组件都保证了它自己的一致性,整个端到端的一致性级别取决于所有组件中一致性最弱的组件
32、端到端的一致性具体可以划分?
内部保证:依赖checkpoint
source端:需要外部源可重设数据的读取位置
sink端:需要保证从故障恢复时,数据不会重复写入外部系统
33、sink端保证一致性的两种方式?
幂等写入
所谓幂等操作,是说一个操作,可以重复执行很多次,但只导致一次结果更改,也就是说,后面再重复执行就不起作用了
事务写入
需要构建事务来写入外部系统,构建的事务对应着checkpoint,等到checkpoint真正完成的时候,才把所有对应的结果写入sink系统中
34、事务性写入具体又有两种实现方式?
预写日志(WAL)
两阶段提交(2PC)
35、Flink + Kafka如何实现端到端的exactly-once语义?
内部:利用checkpoint机制,把状态存盘,发生故障的时候可以恢复,保证内部的状态一致性
source:kafka consumer作为source,可以将偏移量保存下来,如果后续任务出现了故障,恢复的时候可以由连接器重置偏移量,重新消费数据,保证一致性
sink:kafka producer作为sink,采用两阶段提交sink,需要实现一个TwoPhaseCommitSinkFunction
36、Flink的StateBackend?
每传入一条数据,有状态的算子任务都会读取和更新状态
由于有效的状态访问对于处理数据的低延迟至关重要,因此每个并行任务都会在本地维护其状态,以确保快速的状态访问
状态的存储、访问以及维护,由一个可插入的组件决定,这个组件就叫做状态后端(state backend)
37、几种状态后端的区别?
MemoryStateBackend
内存级的状态后端,会将键控状态作为内存中的对象进行管理,将它们存储在TaskManager的JVM堆上,而将checkpoint存储在JobManager的内存中
特点:快速、低延迟,但不稳定
FsStateBackend
将checkpoint存到远程的持久化文件系统(FileSystem)上,而对于本地状态,跟MemoryStateBackend一 样,也会存在TaskManager的JVM堆上
同时拥有内存级的本地访问速度,和更好的容错保证
RocksDBStateBackend
将所有状态序列化后,存入本地的RocksDB中存储
注意:RocksDB的支持并不直接包含在flink中,需要引入依赖