Flink面试题

1, flink和spark有什么区别?flink的优势体现在什么地方?
2, flink的checkpoint是怎么实现的?
3, flink on yarn的启动流程?
4, flink如何实现端到端的exactly-once?
5, 谈谈你对flink状态的认识?
6, 怎么合理的配置flink任务的资源?
7, flink的反压是怎么实现的?
8, flink的watermark是干什么的?具体怎么用?
9, flink的延迟高,怎么调优?
10, flink的双流join是怎么实现的?

➤ 深入原理-Flink 数据交换和 Redistribute 详解?
➤ 深入原理-Flink 执行计划 (Shuffle)?
➤ 深入理解-Flink 内存模型?

Flink 原理与实现:内存管理

在本文中,分为以下几个部分:
第一部分:Flink 中的核心概念和基础篇,包含了 Flink 的整体介绍、核心概念、算子等考察点。
第二部分:Flink 进阶篇,包含了 Flink 中的数据传输、容错机制、序列化、数据热点、反压等实际生产环境中遇到的问题等考察点。
第三部分:Flink 源码篇,包含了 Flink 的核心代码实现、Job 提交流程、数据交换、分布式快照机制、Flink SQL 的原理等考察点。

➤ Flink 相比传统的 Spark Streaming 有什么区别?

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

  1. 架构模型
  • Spark Streaming 在运行时的主要角色包括:Master、Worker、Driver、Executor。
  • Flink 在运行时主要包含:Jobmanager、Taskmanager和Slot。
  1. 任务调度
  • Spark Streaming 连续不断的生成微小的数据批次,构建有向无环图DAG,Spark Streaming 会依次创建 DStreamGraph、JobGenerator、JobScheduler。
  • Flink 根据用户提交的代码生成 StreamGraph,经过优化生成 JobGraph,然后提交给 JobManager进行处理,JobManager 会根据 JobGraph 生成 ExecutionGraph,ExecutionGraph 是 Flink 调度最核心的数据结构,JobManager 根据 ExecutionGraph 对 Job 进行调度。
  1. 时间机制
  • Spark Streaming 支持的时间机制有限,只支持处理时间
  • Flink 支持了流处理程序在时间上的三个定义:处理时间、事件时间、注入时间。同时也支持 watermark 机制来处理滞后数据。
  1. 容错机制
  • 对于 Spark Streaming 任务,我们可以设置 checkpoint,然后假如发生故障并重启,我们可以从上次 checkpoint 之处恢复,但是这个行为只能使得数据不丢失,可能会重复处理,不能做到恰好一次处理语义。
  • Flink 则使用两阶段提交协议来解决这个问题。
  1. 维表join和异步IO
    Structured Streaming不直接支持与维表的join操作,但是可以使用map、flatmap及udf等来实现该功能,所有的这些都是同步算子,不支持异步IO操作。但是Structured Streaming直接与静态数据集的join,可以也可以帮助实现维表的join功能,当然维表要不可变。

Flink支持与维表进行join操作,除了map,flatmap这些算子之外,flink还有异步IO算子,可以用来实现维表,提升性能。

➤ 为什么说flink统一了流和批处理?

因为flink无论是批处理还是流处理,底层都是有状态的流处理,flink执行批处理实际上是流处理的一种特例,只不过此时的流式有界的,而流处理的流式无界的,应用于流处理上的transformation完全可以应用在batch上并且table API和sql都可以用在批处理和流处理上只不过区别在于
a. 容错并不是采用的流式处理的checkpoint,而是直接重新计算
b. dataset api处理的数据是很简单的数据结构,而stream处理的是key/value
c. 流处理在应用transformation和table api和sql的时候不支持topN、limit、sort普通字段等操作

另外从计算模型上来说:批处理每个stage只有完全处理完才会把缓存中(缓存+磁盘)序列化的数据发往下一个stage,而流处理是一条一条,批处理吞吐量大,流处理时效性强,而flink则是采用了折中的方式,在内存中划分缓冲小块,当小块满了就发往下一个stage。如果缓存块无限大,那么就是批处理了。


➤ Flink是如何支持批流一体的?

image

本道面试题考察的其实就是一句话:Flink的开发者认为**批处理流处理**的一种特殊情况。批处理是有限的流处理。Flink 使用一个引擎支持了DataSet API 和 DataStream API。


➤ 你们的Flink集群规模多大?

大家注意,这个问题看起来是问你实际应用中的Flink集群规模,其实还隐藏着另一个问题:Flink可以支持多少节点的集群规模?
在回答这个问题时候,可以将自己生产环节中的集群规模、节点、内存情况说明,同时说明部署模式(一般是Flink on Yarn),除此之外,用户也可以同时在小集群(少于5个节点)和拥有 TB 级别状态的上千个节点上运行 Flink 任务。


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

image

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


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

image

Flink 程序在运行时主要有 TaskManager,JobManager,Client三种角色。

  • JobManager扮演着集群中的管理者Master的角色,它是整个集群的协调者,负责接收Flink Job协调检查点Failover 故障恢复等,同时管理Flink集群中从节点TaskManager。
    a. JobManager 接收待执行的 application。application 包含一个 JobGraph 和 JAR (包含所有需要的classes,libraries 和其他资源)。
    b. JobManager 将 JobGraph 转成 ExecutionGraph,ExecutionGraph中包含可以并发执行的 tasks。
    c. JobManager 向 ResourceManager 申请需要的资源(TaskManager slots),一旦分配到足够的slots,则分发 tasks 到 TaskManager 执行。
    d. 执行期间,JobManager 负责中央协调,如协调checkpoint等

  • TaskManager是实际负责执行计算的Worker,在其上执行Flink Job的一组Task,每个TaskManager负责管理其所在节点上的资源信息,如内存、磁盘、网络,在启动的时候将资源的状态向JobManager汇报。
    a. 启动之后,TaskManager 向 ResourceManager 注册 slots 数,当接收到 ResourceManager 的分配通知后,会向 JobManager 提供一个或多个slots
    b. 紧接着 JobManager 将 tasks 分配到 slots 执行。
    c. 执行期间,不同的 TaskManager 之间会进行数据交换

  • Client是Flink程序提交的客户端,当用户提交一个Flink程序时,会首先创建一个Client,该Client首先会对用户提交的Flink程序进行预处理,并提交到Flink集群中处理,所以Client需要从用户提交的Flink程序配置中获取JobManager的地址,并建立到JobManager的连接,将Flink Job提交给JobManager。


➤ Flink的架构?

主从结构 Jobmanager,taskmanager两个进程(可以把client也加进去)。
集群模式:standalone,on yarn(在yarn上运行一个flink集群/提交到yarn上运行flink job)

Jobmanager: 作用
  1. registerTaskManager:在flink集群启动时,taskmanager会向jobmanager注册
  2. submitjob:flink程序内部通过client向jobmanager提交job,job是以jobgraph形式提交
  3. canceljob:请求取消一个flinkjob
  4. updateTaskExcutionStage:更新taskmanager中excution的状态信息
  5. requestnextinputsplit:运行在taskmanager上的task请求获取下一个要处理的split
  6. jobstatuschanged:executionGraph向jobmanager发送该消息,用来表示job的状态变化
Taskmanager: 作用
  1. 注册:向jobmnager注册自己
  2. 可操作阶段:该阶段taskmanager可以接受并处理与task有关的消息
client: 作用

client对用户提交的代码进行预处理,client将程序组装成一个 jobgraph,它是由多个jobvertex组成的DAG。

关于flink生成dag、提交job、分发task等细节 在任务提交面试题会整理。


➤ Flink 的组件栈有哪些?

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

image

自下而上,每一层分别代表:

  • 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(图处理)。

➤ JobManger在集群中扮演了什么角色?

JobManager 负责整个 Flink 集群任务的调度以及资源的管理,从客户端中获取提交的应用,然后根据集群中 TaskManager 上 TaskSlot 的使用情况,为提交的应用分配相应的 TaskSlot 资源并命令 TaskManager 启动从客户端中获取的应用。

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

➤ 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发送。

➤ TaskManager在集群中扮演了什么角色?

TaskManager 相当于整个集群的 Slave 节点,负责具体的任务执行和对应任务在每个Node上的资源申请管理

  1. 客户端通过将编写好的 Flink 应用编译打包,提交到 JobManager,然后 JobManager 会根据已注册在 JobManager 中 TaskManager 的资源情况,将任务分配给有资源的 TaskManager节点,然后启动并运行任务。
  2. TaskManager 从 JobManager 接收需要部署的任务,然后使用 Slot 资源启动 Task,建立数据接入的网络连接,接收数据并开始数据处理。同时 TaskManager 之间的数据交互都是通过数据流的方式进行的。

可以看出,Flink 的任务运行其实是采用多线程的方式,这和 MapReduce 多 JVM 进行的方式有很大的区别,Flink 能够极大提高 CPU 使用效率,在多个任务和 Task 之间通过 TaskSlot 方式共享系统资源,每个 TaskManager 中通过管理多个 TaskSlot 资源池进行对资源进行有效管理。


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

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


➤ flink中应用在tableAPI中的UDF有几种?
  1. scalar function:针对一条record的一个字段的操作,返回一个字段
  2. table function:针对一条record的一个字段的操作,返回多个字段
  3. aggregate function:针对多条记录的一个字段操作,返回一条记录

➤ 你知道UDF吧,请问我们注册UDF到底是每个计算线程一份还是每个executor一份?或者说是多个对象还是共享一个对象?如果答的对的话,面试官会问你如何保证共享呢,这就涉及单例对象的问题了。这个问题有点乱,请自行整理。(头条)

我们要知道一般来说在使用一个类的时候,一般是要创建对象的,所以我们在sql里使用UDF的时候会创建对象,如果是多线程并行操作sql,那么就是多个UDF对象。那么如何保证一个executer进程中共享一个UDF呢,在scala中就用Object即可。如果是class就写一个单例模式,关于单例模式算法题中我会详细整理!


➤ 你知道flink可以修改代码恢复吧!但是不是所有的修改都可以恢复哦,请问什么样的代码修改会导致无法flink任务恢复?(头条)

面试官说:只有当不会改变DAG的修改才会正常恢复!!!有机会试一下。


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

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


➤ Flink是如何做容错的?

Flink 实现容错主要靠强大的 CheckPoint机制State机制

  1. Checkpoint 负责定时制作分布式快照、对程序中的 State 状态进行备份;
  2. State 用来存储计算过程中的中间状态。

➤ flink的 Checkpoint 机制详细讲一下?注意与spark的区别?

flink是通过checkpoint机制实现容错,它的原理是不断的生成分布式streaming数据流snapshot快照。在流处理失败时通过这些snapshot可以恢复数据流处理。而flink的快照有两个核心:

  • barrier 机制:barrier是实现checkpoint的机制。
  • state 状态保存:state保存则是通过barrier这种机制进行 分布式快照 的实现。
1. barrier

barrier是checkpoint的核心,他会当做记录打入数据流,从而将数据流分组,并沿着数据流方向向前推进,每个barrier会携带一个snapshotID,属于该snapshot的记录会被推向该barrier的前方。所以barrier之后的属于下一个ckeckpoint期间(snapshot中)的数据。然后当中间的operation接收到barrier后,会发送barrier到属于该barrier的snapshot的数据流中,等到sink operation接收到该barrier后会向checkpoint coordinator确认该snapshot,直到所有的sink operation都确认了该snapshot,才会认为完成了本次checkpoint或者本次snapshot。

理解:可以认为barrier这种机制是flink实现分布式快照的手段。那么在这个过程中要记录state快照信息,到底有哪些信息需要序列话呢?

在说state保存之前我们要知道flink的三种方式,

  1. jobmanager内存,不建议;
  2. hdfs(可以使用,同步 进行分布式快照);
  3. rocksDB(异步 进行分布式快照)。

除了第3种其他两种都是同步快照。也就是说用hdfs这种方式快照是会阻塞数据处理的,只有当两个barrier之间数据处理完成并完成快照之后才向下一个task发送数据并打入barrier n。我们不管异步快照,我们现在只说同步快照。

2. state状态保存

state状态保存分为两种:

  1. 一种是用户自定义状态:也就是我们为了实现需求敲的代码(算子),他们来创建和修改的state;
  2. 一种是系统状态:此状态可以认为数据缓冲区,比如window窗口函数,我们要知道数据处理的情况。

生成的快照现在包含:

  1. 对于每个并行流数据源,创建快照时流中的偏移/位置
  2. 对于每个运算符,存储在快照中的状态指针
3. stream aligning (barrier k对齐)

这个情况出现的很少,用于解决同一个Operation处理多个输入流的情况(不是同一个数据源),这种情况下operation将先收到barrier k的数据缓存起来不进行处理,只有当另一个流的barrier k到达之后再进行处理,同时opeartion会向checkpoint coordinator上报snapshot。这就是barrier k对齐

SparkCheckpoint

spark的checkpoint的方式没有这么复杂,直接通过记录metadata和data的方式来进行checkpoint。从checkpoint中恢复时ss是决不允许修改代码的,而sss是有些情况可以接受修改代码的。

a. metadata checkpoint
将定义流式计算的信息保存到hdfs:配置、dstream操作、尚未完成的批次

b. data checkpoint
这就比较直接了,直接持久化RDD到hdfs,因为我们知道spark的容错就是基于rdd的血缘关系的,而为了避免依赖关系链太长,spark会定期从最新的rdd中持久化数据到hdfs。

注意:::如果spark程序中没有updateStateByKey或reduceByKeyAndWindow这种带有状态持续改变的算子操作的时候完全可以不用对rdd进行持久化,只需要利用metadata来恢复程序即可,因为数据的丢失时可以接受的,但是如果存在状态转换的算法就不行了。


➤ Flink 分布式快照 Checkpoint 的原理是什么?

Flink的分布式快照是根据Chandy-Lamport算法量身定做的。简单来说就是持续创建分布式数据流及其状态的一致快照。

image

核心思想:是在 input source 端插入 barrier,控制 barrier 的同步来实现 snapshot 的备份exactly-once 语义

➤ Flink 是如何保证Exactly-once语义的?

Flink通过实现 两阶段提交状态保存 来实现 端到端 的一致性语义。 分为以下几个步骤:

  1. 开始事务(beginTransaction)创建一个临时文件夹,来写把数据写入到这个文件夹里面
  2. 预提交(preCommit)将内存中缓存的数据写入文件并关闭
  3. 正式提交(commit)将之前写完的临时文件放入目标目录下。这代表着最终的数据会有一些延迟
  4. 丢弃(abort)丢弃临时文件
自己整理的版本
  • 使用 支持 Exactly-Once 数据源
  • 使用 FlinkKafkaConsumer, 开启 checkpointing,把偏移量通过 checkpoint 机制保存到 StateBackend 中,并且默认会将偏移量写入到 Kafka __consumer_offset Topic 中。
  • FlinkKafkaConsumer.setCommitOffsetsOnCheckpoints 默认为 true,即将偏移量写入到 Kafka __consumer_offset 中,目的是为了监控或重启任务时,没有指定 savepoint 可以接着一起的偏移量继续消费。
  • 设置 CheckpointingMode.EXACTLY_ONCE
  • 存储系统支持覆盖(Redis, Hbase, ES) 使用幂等性,覆盖原来的数据。
  • Barrier 可以保证一个流水线中所有算子都处理完了,再对该条数据做 Checkpoint.
  • 存储系统不支持覆盖,要支持事务,成功:提交事务,更新偏移量;失败:回滚事务,不更新偏移量,放弃这次 Checkpoint ,标记为失败状态,继续下一次Checkpoint。
    a. 特点是:可以保证提交事务和 Checkpointing 同时成功。

若失败发生在预提交成功后,正式提交前。可以根据状态来提交预提交的数据,也可删除预提交的数据。

➤ 请问Flink到底是如何保证端到端的exactly once语义的?请从source——算子——算子——sink整个流程说明。可以从kafka的sink或者producer说起。需要注意的是ckeckpoint和offset提交的先后顺序,可以看一下源码。貌似与flink的两端提交有关。

可以从两方面阐述:
第一:flink的checkpoint机制可以保证at least once消费语义
第二:flink的两段式提交commit保证了端对端的exactly once消费语义(TwoPhaseCommitSinkFunction)

尤其是在kafka0.11版本开始,支持两段式提交

Flink1.4之前只能在flink内存保证exactly once语义,但是很多时候flink要对接其他系统,那么就要实现commit提交和rollback回滚机制,而分布式系统中两段提交和回滚就是实现方式。因为很多算子包括sink都是并行的,我们不能通过sink的一次commit就完成了最终的commit,因为假如有10的sink,其中9个sink commit了第十个失败了,那么这个过程我们还是无法回滚!!所以需要分布式两段提交策略。

2阶段提交的思想?
  1. pre-commit
  2. commit,

所谓pre-commit指的是第一阶段,也就是checkpoint阶段完成时进行pre-commit,如果所有的pre-commit成功,jobmanager会通知所有跟外部系统有联系的比如sink,通知他们进行第二阶段的commit!这就是两段式提交实现的flink的exactly once消费语义。


➤ 为什么要开启 Checkpoint?

开启 Checkpoint 机制主要是为了实现 实时任务处理的容错
实时任务不同于批处理任务,除非用户主动停止,一般会一直运行,运行的过程中可能存在机器故障、网络问题、外界存储问题等等,要想实时任务一直能够稳定运行,实时任务要有自动容错恢复的功能。
而批处理任务在遇到异常情况时,在重新计算一遍即可。实时任务因为会一直运行的特性,如果在从头开始计算,成本会很大,尤其是对于那种运行时间很久的实时任务来说。
实时任务开启 Checkpoint 功能,也能够减少容错恢复的时间。因为每次都是从最新的 Chekpoint 点位开始状态恢复,而不是从程序启动的状态开始恢复。


➤ Flink Checkpoint 常见失败原因分析?

Flink Checkpoint 失败有很多种原因,常见的失败原因如下:

  • 用户代码逻辑没有对于异常处理,让其直接在运行中抛出。比如解析 Json 异常,没有捕获,导致 Checkpoint失败,或者调用 Dubbo 超时异常等等。
  • 依赖外部存储系统,在进行数据交互时,出错,异常没有处理。比如输出数据到 Kafka、Redis、HBase等,客户端抛出了超时异常,没有进行捕获,Flink 任务容错机制会再次重启。
  • 内存不足,频繁GC,超出了 GC 负载的限制。比如 OOM 异常
  • 网络问题、机器不可用问题等等。

从目前的具体实践情况来看,Flink Checkpoint 异常觉大多数还是用户代码逻辑的问题,对于程序异常没有正确的处理导致。所以在编写 Flink 实时任务时,一定要注意处理程序可能出现的各种异常。这样,也会让实时任务的逻辑更加的健壮。


➤ Flink Checkpoint 太频繁,或时间太久会有什么影响?

checkpoint 的执行间隔要根据实际业务情况配置,checkpoint次数据太频繁,容易给后端系统造成压力。checkpoint 间隔时间太久,状态数据恢复时间较长。


➤ Flink checkpoint 成功后,会不会删除之前的 checkpoint 数据?Flink 会生成多少个 checkpoint文件?

checkpoint执行成功后,会自动删除之前保存的 checkpoint 数据。有多少个 SubTask就会生成多少个 checkpoint 文件。每个 SubTask 保存自己的数据。
image.png

image.png


➤ Flink的 BackPressure 背压机制,跟spark有什么区别?
  1. Flink是通过自下而上背压检测从而 控制流量。如果下层的operation压力大那么上游的operation就会让它慢下来。Jobmanager会反复调用一个job的task运行所在线程的Thread.getStackTrace(),默认情况下,jobmanager会每个50ms触发对一个job的每个task依次进行100次堆栈跟踪调用,根据调用结果来确定backpressure,flink是通过计算得到一个比值radio来确定当前运行的job的backpressure状态。在web页面可以看到这个radio值,它表示在一个内部方法调用中阻塞
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值