​大数据面试题——Flink面试进阶篇

时间:2022-10-09 13:12:51

1 Flink Job的提交流程

用户提交的Flink Job会被转化成一个DAG任务运行,分别是:StreamGraph、JobGraph、ExecutionGraph,Flink中JobManager与TaskManager,JobManager与Client的交互是基于Akka工具包的,是通过消息驱动。整个Flink Job的提交还包含着ActorSystem的创建,JobManager的启动,TaskManager的启动和注册。

2 Flink所谓"三层图"结构是哪几个"图"?

一个Flink任务的DAG生成计算图大致经历以下三个过程:

StreamGraph最接近代码所表达的逻辑层面的计算拓扑结构,按照用户代码的执行顺序向StreamExecutionEnvironment添加StreamTransformation构成流式图。

JobGraph从StreamGraph生成,将可以串联合并的节点进行合并,设置节点之间的边,安排资源共享slot槽位和放置相关联的节点,上传任务所需的文件,设置检查点配置等。相当于经过部分初始化和优化处理的任务图。

ExecutionGraph由JobGraph转换而来,包含了任务具体执行所需的内容,是最贴近底层实现的执行图。

3 JobManger在集群中扮演了什么角***>

JobManager负责整个Flink集群任务的调度以及资源的管理,从客户端中获取提交的应用,然后根据集群中TaskManager上TaskSlot的使用情况,为提交的应用分配相应的TaskSlot资源并命令TaskManager启动从客户端中获取的应用。JobManager相当于整个集群的Master节点,且整个集群有且只有一个活跃的JobManager,负责整个集群的任务管理和资源管理。JobManager和TaskManager之间通过Actor System进行通信,获取任务执行的情况并通过Actor System将应用的任务执行情况发送给客户端。同时在任务执行的过程中,Flink JobManager会触发Checkpoint操作,每个TaskManager节点 收到Checkpoint触发指令后,完成Checkpoint操作,所有的Checkpoint协调过程都是在Fink JobManager中完成。当任务完成后,Flink会将任务执行的信息反馈给客户端,并且释放掉TaskManager中的资源以供下一次提交任务使用。

4 JobManger在集群启动过程中起到什么作用?

JobManager的职责主要是接收Flink作业,调度Task,收集作业状态和管理TaskManager。它包含一个Actor,并且做如下操作:

RegisterTaskManager:它由想要注册到JobManager的TaskManager发送。注册成功会通过AcknowledgeRegistration消息进行Ack。

SubmitJob:由提交作业到系统的Client发送。提交的信息是JobGraph形式的作业描述信息。

CancelJob:请求取消指定id的作业。成功会返回CancellationSuccess,否则返回CancellationFailure。

UpdateTaskExecutionState:由TaskManager发送,用来更新执行节点(ExecutionVertex)的状态。成功则返回true,否则返回false。

RequestNextInputSplit: TaskManager上的Task请求下一个输入split,成功则返回NextInputSplit,否则返回null。

JobStatusChanged: 它意味着作业的状态(RUNNING, CANCELING, FINISHED,等)发生变化。这个消息由ExecutionGraph发送。

5 TaskManager在集群中扮演了什么角***>

TaskManager相当于整个集群的Slave节点,负责具体的任务执行和对应任务在每个节点上的资源申请和管理。客户端通过将编写好的Flink应用编译打包,提交到JobManager,然后JobManager会根据已注册在JobManager中TaskManager的资源情况,将任务分配给有资源的TaskManager节点,然后启动并运行任务。TaskManager从JobManager接收需要部署的任务,然后使用Slot资源启动Task,建立数据接入的网络连接,接收数据并开始数据处理。同时TaskManager之间的数据交互都是通过数据流的方式进行的。可以看出,Flink的任务运行其实是采用多线程的方式,这和MapReduce多JVM进行的方式有很大的区别,Flink能够极大提高CPU使用效率,在多个任务和Task之间通过TaskSlot方式共享系统资源,每个TaskManager中通过管理多个TaskSlot资源池进行对资源进行有效管理。

6 TaskManager在集群启动过程中起到什么作用?

TaskManager的启动流程较为简单: 启动类:org.apache.flink.runtime.taskmanager.TaskManager核心启动方法 : selectNetworkInterfaceAndRunTaskManager启动后直接向JobManager注册自己,注册完成后,进行部分模块的初始化。

7 Flink计算资源的调度是如何实现的?

TaskManager中最细粒度的资源是Task slot,代表了一个固定大小的资源子集,每个TaskManager会将其所占有的资源平分给它的slot。

通过调整task slot的数量,用户可以定义task之间是如何相互隔离的。每个TaskManager有一个slot,也就意味着每个task运行在独立的JVM中。每个TaskManager有多个slot的话,也就是说多个task运行在同一个JVM中。

而在同一个JVM进程中的task,可以共享TCP连接(基于多路复用)和心跳消息,可以减少数据的网络传输,也能共享一些数据结构,一定程度上减少了每个task的消耗。 每个slot可以接受单个task,也可以接受多个连续task组成的pipeline,如下图所示,FlatMap函数占用一个taskslot,而key Agg函数和sink函数共用一个taskslot:

​大数据面试题——Flink面试进阶篇

8简述Flink的数据抽象及数据交换过程?

Flink为了避免JVM的固有缺陷例如java对象存储密度低,FGC影响吞吐和响应等,实现了自主管理内存。MemorySegment就是Flink的内存抽象。默认情况下,一个MemorySegment可以被看做是一个32kb大的内存块的抽象。这块内存既可以是JVM里的一个byte[],也可以是堆外内存(DirectByteBuffer)。在MemorySegment这个抽象之上,Flink在数据从operator内的数据对象在向TaskManager上转移,预备被发给下个节点的过程中,使用的抽象或者说内存对象是Buffer。对接从Java对象转为Buffer的中间对象是另一个抽象StreamRecord。

9 Flink中的分布式快照机制是如何实现的?

Flink的容错机制的核心部分是制作分布式数据流和操作算子状态的一致性快照。 这些快照充当一致性checkpoint,系统可以在发生故障时回滚。 Flink用于制作这些快照的机制在“分布式数据流的轻量级异步快照”中进行了描述。 它受到分布式快照的标准Chandy-Lamport算法的启发,专门针对Flink的执行模型而定制。

​大数据面试题——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之前的记录,因为此时这些记录(及其后续记录)将已经通过整个数据流拓扑,也即是已经被处理结束。

10简单说说FlinkSQL的是如何实现的?

Flink将SQL校验、SQL解析以及SQL优化交给了Apache Calcite。Calcite在其他很多开源项目里也都应用到了,譬如Apache Hive, Apache Drill, Apache Kylin, Cascading。Calcite在新的架构中处于核心的地位,如下图所示。

​大数据面试题——Flink面试进阶篇

 

​大数据面试题——Flink面试进阶篇

构建抽象语法树的事情交给了Calcite去做。SQL query会经过Calcite解析器转变成SQL节点树,通过验证后构建成Calcite的抽象语法树(也就是图中的Logical Plan)。另一边,Table API上的调用会构建成Table API的抽象语法树,并通过Calcite提供的RelBuilder转变成Calcite的抽象语法树。然后依次被转换成逻辑执行计划和物理执行计划。在提交任务后会分发到各个TaskManager中运行,在运行时会使用Janino编译器编译代码后运行。


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及多种图计算算法实现。根据官网的介绍,Flink的特性包含:

2、Flink相比传统的Spark Streaming区别?

这个问题是一个非常宏观的问题,因为两个框架的不同点非常之多。但是在面试时有非常重要的一点一定要回答出来:Flink是标准的实时处理引擎,基于事件驱动。而Spark Streaming是微批(Micro-Batch)的模型。

下面我们就分几个方面介绍两个框架的主要区别:

1.架构模型Spark Streaming在运行时的主要角色包括:Master、Worker、Driver、Executor,Flink在运行时主要包含:Jobmanager、Taskmanager和Slot。

2.任务调度Spark Streaming连续不断的生成微小的数据批次,构建有向无环图DAG,Spark Streaming会依次创建DStreamGraph、JobGenerator、JobScheduler。Flink根据用户提交的代码生成StreamGraph,经过优化生成JobGraph,然后提交给JobManager进行处理,JobManager会根据JobGraph生成ExecutionGraph,ExecutionGraph是Flink调度最核心的数据结构,JobManager根据ExecutionGraph对Job进行调度。

3.时间机制Spark Streaming支持的时间机制有限,只支持处理时间。 Flink支持了流处理程序在时间上的三个定义:处理时间、事件时间、注入时间。同时也支持 watermark 机制来处理滞后数据。

4.容错机制对于Spark Streaming任务,我们可以设置checkpoint,然后假如发生故障并重启,我们可以从上次checkpoint之处恢复,但是这个行为只能使得数据不丢失,可能会重复处理,不能做到恰好一次处理语义。Flink则使用两阶段提交协议来解决这个问题。

3、Flink的组件栈有哪些?

根据Flink官网描述,Flink是一个分层架构的系统,每一层所包含的组件都提供了特定的抽象,用来服务于上层组件。

​大数据面试题——Flink面试进阶篇

自下而上,每一层分别代表:Deploy层:该层主要涉及了Flink的部署模式,在上图中我们可以看出,Flink支持包括local、Standalone、Cluster、Cloud等多种部署模式。Runtime层:Runtime层提供了支持Flink计算的核心实现,比如:支持分布式Stream处理、JobGraph到ExecutionGraph的映射、调度等等,为上层API层提供基础服务。API层:API层主要实现了面向流(Stream)处理和批(Batch)处理API,其中面向流处理对应DataStream API,面向批处理对应DataSet API,后续版本,Flink有计划将DataStream和DataSet API进行统一。Libraries层:该层称为Flink应用框架层,根据API层的划分,在API层之上构建的满足特定应用的实现计算框架,也分别对应于面向流处理和面向批处理两类。面向流处理支持:CEP(复杂事件处理)、基于SQL-like的操作(基于Table的关系操作);面向批处理支持:FlinkML(机器学习库)、Gelly(图处理)。

4、Flink的运行必须依赖Hadoop组件吗?

Flink可以完全独立于Hadoop,在不依赖Hadoop组件下运行。但是做为大数据的基础设施,Hadoop体系是任何大数据框架都绕不过去的。Flink可以集成众多Hadooop组件,例如Yarn、Hbase、HDFS等等。例如,Flink可以和Yarn集成做资源调度,也可以读写HDFS,或者利用HDFS做检查点。


6 Flink的基础编程模型了解吗?

​大数据面试题——Flink面试进阶篇

上图是来自Flink官网的运行流程图。通过上图我们可以得知,Flink程序的基本构建是数据输入来自一个Source,Source代表数据的输入端,经过Transformation进行转换,然后在一个或者多个Sink接收器中结束。数据流(stream)就是一组永远不会停止的数据记录流,而转换(transformation)是将一个或多个流作为输入,并生成一个或多个输出流的操作。执行时,Flink程序映射到streaming dataflows,由流(streams)和转换操作(transformation operators)组成。

7 Flink集群有哪些角色?各自有什么作用?

​大数据面试题——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。

8 说说Flink资源管理中Task Slot的概念

​大数据面试题——Flink面试进阶篇

在Flink架构角色中我们提到,TaskManager是实际负责执行计算的Worker,TaskManager是一个JVM进程,并会以独立的线程来执行一个task或多个subtask。为了控制一个TaskManager能接受多少个task,Flink提出了Task Slot的概念。简单的说,TaskManager会将自己节点上管理的资源分为不同的Slot:固定大小的资源子集。这样就避免了不同Job的Task互相竞争内存资源,但是需要主要的是,Slot只会做内存的隔离。没有做CPU的隔离。

9 说说Flink的常用算子?

Flink最常用的常用算子包括:Map:DataStream → DataStream,输入一个参数产生一个参数,map的功能是对输入的参数进行转换操作。Filter:过滤掉指定条件的数据。KeyBy:按照指定的key进行分组。Reduce:用来进行结果汇总合并。Window:窗口函数,根据某些特性将每个key的数据进行分组(例如:在5s内到达的数据)

10 说说你知道的Flink分区策略?

什么要搞懂什么是分区策略。分区策略是用来决定数据如何发送至下游。目前Flink支持了8中分区策略的实现。

​大数据面试题——Flink面试进阶篇

上图是整个Flink实现的分区策略继承图:GlobalPartitioner 数据会被分发到下游算子的第一个实例中进行处理。ShufflePartitioner 数据会被随机分发到下游算子的每一个实例中进行处理。RebalancePartitioner 数据会被循环发送到下游的每一个实例中进行处理。RescalePartitioner 这种分区器会根据上下游算子的并行度,循环的方式输出到下游算子的每个实例。这里有点难以理解,假设上游并行度为2,编号为A和B。下游并行度为4,编号为1,2,3,4。那么A则把数据循环发送给1和2,B则把数据循环发送给3和4。假设上游并行度为4,编号为A,B,C,D。下游并行度为2,编号为1,2。那么A和B则把数据发送给1,C和D则把数据发送给2。BroadcastPartitioner 广播分区会将上游数据输出到下游算子的每个实例中。适合于大数据集和小数据集做Jion的场景。ForwardPartitioner ForwardPartitioner用于将记录输出到下游本地的算子实例。它要求上下游算子并行度一样。简单的说,ForwardPartitioner用来做数据的控制台打印。KeyGroupStreamPartitioner Hash分区器。会将数据按Key的Hash值输出到下游算子实例中。CustomPartitionerWrapper 用户自定义分区器。需要用户自己实现Partitioner接口,来定义自己的分区逻辑。例如:


static classCustomPartitionerimplementsPartitioner<String> { @Override publicintpartition(String key, int numPartitions) {

switch (key){

case "1":

return 1;

case "2":

return 2;

case "3":

return 3;

default:

return 4;

}

}

}


11 Flink的并行度了解吗?Flink的并行度设置是怎样的?

Flink中的任务被分为多个并行任务来执行,其中每个并行的实例处理一部分数据。这些并行实例的数量被称为并行度。我们在实际生产环境中可以从四个不同层面设置并行度:

操作算子层面(Operator Level)

执行环境层面(Execution Environment Level)

客户端层面(Client Level)

系统层面(System Level)

需要注意的优先级:算子层面>环境层面>客户端层面>系统层面。

12 Flink的Slot和parallelism有什么区别?

官网上十分经典的图:

​大数据面试题——Flink面试进阶篇

slot是指taskmanager的并发执行能力,假设我们将taskmanager.numberOfTaskSlots配置为3那么每一个taskmanager中分配3个TaskSlot, 3个taskmanager一共有9个TaskSlot。

​大数据面试题——Flink面试进阶篇

parallelism是指taskmanager实际使用的并发能力。假设我们把parallelism.default设置为1,那么9个TaskSlot只能用1个,有8个空闲。

13 Flink有没有重启策略?说说有哪几种?

Flink实现了多种重启策略。

固定延迟重启策略(Fixed Delay Restart Strategy)

故障率重启策略(Failure Rate Restart Strategy)

没有重启策略(No Restart Strategy)

Fallback重启策略(Fallback Restart Strategy)


14用过Flink中的分布式缓存吗?如何使用?

Flink实现的分布式缓存和Hadoop有异曲同工之妙。目的是在本地读取文件,并把他放在taskmanager节点中,防止task重复拉取。


val env = ExecutionEnvironment.getExecutionEnvironment

// register a file from HDFS
env.registerCachedFile("hdfs:///path/to/your/file", "hdfsFile")

// register a local executable file (script, executable, ...)
env.registerCachedFile("file:///path/to/exec/file", "localExecFile", true)

// define your program and execute

...

val input: DataSet[String] = ...

val result: DataSet[Integer] = input.map(new MyMapper())

...

env.execute()


15说说Flink中的广播变量,使用时需要注意什么?

我们知道Flink是并行的,计算过程可能不在一个Slot中进行,那么有一种情况即:当我们需要访问同一份数据。那么Flink中的广播变量就是为了解决这种情况。我们可以把广播变量理解为是一个公共的共享变量,我们可以把一个dataset数据集广播出去,然后不同的task在节点上都能够获取到,这个数据在每个节点上只会存在一份。

16说说Flink中的窗口?

来一张官网经典的图:

​大数据面试题——Flink面试进阶篇

Flink支持两种划分窗口的方式,按照time和count。如果根据时间划分窗口,那么它就是一个time-window如果根据数据划分窗口,那么它就是一个count-window。flink支持窗口的两个重要属性(size和interval)如果size=interval,那么就会形成tumbling-window(无重叠数据)如果size>interval,那么就会形成sliding-window(有重叠数据)如果size< interval,那么这种窗口将会丢失数据。比如每5秒钟,统计过去3秒的通过路口汽车的数据,将会漏掉2秒钟的数据。通过组合可以得出四种基本窗口:

time-tumbling-window无重叠数据的时间窗口,设置方式举例:timeWindow(Time.seconds(5))

time-sliding-window有重叠数据的时间窗口,设置方式举例:timeWindow(Time.seconds(5), Time.seconds(3))

count-tumbling-window无重叠数据的数量窗口,设置方式举例:countWindow(5)

count-sliding-window有重叠数据的数量窗口,设置方式举例:countWindow(5,3)

17说说Flink中的状态存储?

Flink在做计算的过程中经常需要存储中间状态,来避免数据丢失和状态恢复。选择的状态存储策略不同,会影响状态持久化如何和checkpoint交互。Flink提供了三种状态存储方式:MemoryStateBackend、FsStateBackend、RocksDBStateBackend。

18 Flink中的时间有哪几类

Flink中的时间和其他流式计算系统的时间一样分为三类:事件时间,摄入时间,处理时间三种。如果以EventTime为基准来定义时间窗口将形成EventTimeWindow,要求消息本身就应该携带EventTime。如果以IngesingtTime为基准来定义时间窗口将形成IngestingTimeWindow,以source的systemTime为准。如果以ProcessingTime基准来定义时间窗口将形成ProcessingTimeWindow,以operator的systemTime为准。

19 Flink中水印是什么概念,起到什么作用?

Watermark是Apache Flink为了处理EventTime窗口计算提出的一种机制,本质上是一种时间戳。 一般来讲Watermark经常和Window一起被用来处理乱序事件。

20 Flink Table & SQL熟悉吗?TableEnvironment这个类有什么作用

TableEnvironment是Table API和SQL集成的核心概念。这个类主要用来:

在内部catalog中注册表

注册外部catalog

执行SQL查询

注册用户定义(标量,表或聚合)函数

将DataStream或DataSet转换为表

持有对ExecutionEnvironment或StreamExecutionEnvironment的引用

21 Flink SQL的实现原理是什么?是如何实现SQL解析的呢?

首先大家要知道Flink的SQL解析是基于Apache Calcite这个开源框架。

​大数据面试题——Flink面试进阶篇

基于此,一次完整的SQL解析过程如下:

用户使用对外提供Stream SQL的语法开发业务应用

用calcite对StreamSQL进行语法检验,语法检验通过后,转换成calcite的逻辑树节点;最终形成calcite的逻辑计划

采用Flink自定义的优化规则和calcite火山模型、启发式模型共同对逻辑树进行优化,生成最优的Flink物理计划

对物理计划采用janino codegen生成代码,生成用低阶API DataStream描述的流应用,提交到Flink平台执行