第一部分:Flink基础篇

第二部分:Flink 进阶篇

第三部分:Flink 源码篇

第一部分:Spark基础篇_奔跑者-辉的博客-CSDN博客 (**往期总结**)

Flink 是 Apache 基金会旗下的一个开源大数据实时处理框架。目前,Flink 已经成为各大公司大数据实时处理的发力重点,特别是国内以阿里为代表的一众互联网大厂都在全力投入,为 Flink 社区贡献了大量源码,如今 Flink 已被很多人认为是大数据实时处理的方向和未来。时至今日,Flink 已经发展到 1.14 版本,在大数据领域对于 Flink 的考察已经是大数据求职者必须面对的,本文结合自己的经验详细总结了近 50 个关于 Flink 的面试考察点。

简单介绍一下Flink(原理)

Flink 是一个流处理框架和分布式处理引擎,用于对无界和有界数据流进行有状态计算。并且 Flink 提供了数据分布、容错机制以及资源管理等核心功能。Flink提供了诸多高抽象层的API以便用户编写分布式任务:

(1) 有状态流处理:底层API什么都能做;

(2.1) DataSet API: 对静态数据进行批处理操作,将静态数据抽象成分布式的数据集,用户可以方便地使用Flink提供的各种操作符对分布式数据集进行处理,支持Java、Scala和Python;

(2.2) DataStream API:对数据流进行流处理操作,将流式的数据抽象成分布式的数据流,用户可以方便地对分布式数据流进行各种操作,支持Java和Scala。

(3) Table API:对结构化数据进行查询操作,将结构化数据抽象成关系表,并通过类SQL的DSL对关系表进行各种查询操作,支持Java和Scala;

(4) SQL: 把TableAPI中数据转换为表,然后写sql去查询。


此外,Flink 还针对特定的应用领域提供了领域库,例如: Flink ML,Flink 的机器学习库,提供了机器学习Pipelines API并实现了多种机器学习算法。 Gelly,Flink 的图计算库,提供了图计算的相关API及多种图计算算法实现。

Flink特点

高吞吐、低延迟
结果的精准一次性保证(exactly-once)
可以与众多常用存储系统连接,实现24小时全天候实时计算运行。


Flink发展的时间线

 Flink集群有哪些角色?(Flink架构)

Flink程序在运行时主要有JobManager,TaskManager,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。

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 则使用两阶段提交协议来解决这个问题。

Yarn模式Per-job⽅式任务提交流程

① Flink任务提交后,Client向HDFS上传Flink的Jar包和配置;

②之后客户端向Yarn ResourceManager提交job任务,ResourceManager分配Container资源 并通知对应的NodeManager启动ApplicationMaster;

③ApplicationMaster启动后加载Flink的Jar包和配置 构建环境,去启动JobManager,之后JobManager向Flink自身的RM进行申请资源,自身的RM向Yarn 的ResourceManager申请资源(因为是yarn模式,所有资源归yarn RM管理)来启动TaskManager

④Yarn ResourceManager分配Container资源后,由ApplicationMaster通知资源所在节点的NodeManager启动TaskManager;

⑤NodeManager加载Flink的Jar包和配置构建环境并启动TaskManager,TaskManager启动后向JobManager发送心跳包,并等待JobManager向其分配任务。

Flink CDC

CDC是Change Data Capture(变更数据获取)的简称。核心思想是,监测并捕获数据库的变动(包括数据或数据表的插入、更新以及删除等),将这些变更按发生的顺序完整记录下来,写入到消息中间件中,以供其他服务进行订阅及消费。

Flink社区开发了Flink-cdc-connectors组件,这是一个可以直接从 MySQL、PostgreSQL、Oracle等数据库直接读取全量数据和增量变更数据的source组件。

通常:
① mysql开启binlog
② canal同步binlog数据写入到kafka
③ flink读取kakfa中的binlog数据进行相关的业务处理。


FlinkCDC也就是说,数据不再通过canal与kafka进行同步,而flink直接进行处理mysql的数据。节省了canal与kafka的过程。

目前Flink SQL CDC 内置了 Debezium引擎 , (支持全量、增量同步,同时支持 MySQL、PostgreSQL、Oracle等数据库),将changelog 转换为 Flink SQL 认识的 RowData 数据(一行数据),使用较为广泛。

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

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

Flink常用算子

Map:      DataStream → DataStream,输入一个参数产生一个参数,map的功能是对输入的参数进行转换操作;
Filter:     过滤掉指定条件的数据;
FlatMap:一般用于列表等数据的压平拆分
KeyBy:   按照指定的key进行分组;
Reduce: 用来进行结果汇总合并;
Window: 窗口函数,根据某些特性将每个key的数据进行分组(例如:在5s内到达的数据)

Flink的三种时间语义(时间机制)

flink的三种时间语义(时间机制)
Event Time:数据本身真正产生的时间,(生产环境中用这个)
Ingestion Time:是数据进入Flink的时间。
Processing Time:Flink中算子处理数据的时间。默认的时间属性就是Event Time。

Flink中的窗口(分类、生命周期、触发、划分)

1)窗口分类: Keyed Window和Non-keyed Window
    基于时间:滚动、滑动、会话
    基于数量:滚动、滑动
2)Window口的4个相关重要组件:

  • assigner(分配器):如何将元素分配给窗口
  • function(计算函数):为窗口定义的计算。其实是一个计算函数,完成窗口内容的计算
  • triger(触发器):在什么条件下触发窗口的计算
  • evictor(退出器):定义从窗口中移除数据

3)窗口的划分:如,基于事件时间的滚动窗口
start=按照数据的事件时间向下取窗口长度的整数倍
end=start+size
比如开了一个10s的滚动窗口,第一条数据是857s,那么它属于[850s,860s)
4)窗口的创建:当属于某个窗口的第一个元素到达,Flink就会创建一个窗口,
5)窗口的销毁:当时间超过其结束时间+用户指定的允许延迟时间(Flink保证只删除基于时间的窗口,而不能删除其他类型的窗口,例如全局窗口)。
6)窗口为什么左闭右开:属于窗口的最大时间戳=end-1ms
7)窗口什么时候触发:如基于事件时间的窗口 watermark>=end-1ms

我们使用的Source和Sink主要是Kafka:
    作为source可以重发,由Flink维护offset,作为状态存储
    作为sink官方的实现类是基于两阶段提交,能保证写入的Exactly-Once
如果下级存储不支持事务:
具体实现是
幂等写入,需要下级存储具有幂等性写入特性。
比如结合HBase的rowkey的唯一性、数据的多版本,实现幂等。

Flink是如何做到高效的数据交换的?
 

在一个Flink Job中,数据需要在不同的task中进行交换,整个数据交换是由TaskManager负责的,TaskManager 的网络组件首先从缓冲buffer中收集records,然后再发送。Records并不是一个一个被发送的,而是积累一个批次再发送,同时batch技术可以更加高效的利用网络资源。

介绍Flink的CEP机制
 

CEP全称为Complex Event Processing,复杂事件处理
Flink CEP是在Flink中实现的复杂事件处理(CEP)库
CEP允许在无休止的事件流中检测事件模式,让我们有机会掌握数据中重要的部分。

Flink CEP 编程中当状态没有到达的时候会将数据保存在哪里?

在流式处理中,CEP 当然是要支持 EventTime 的,那么相对应的也要支持数据的迟到现象,也就是watermark的处理逻辑。CEP对未匹配成功的事件序列的处理,和迟到数据是类似的。在 Flink CEP的处理逻辑中,状态没有满足的和迟到的数据,都会存储在一个Map数据结构中,也就是说,如果我们限定判断事件序列的时长为5分钟,那么内存中就会存储5分钟的数据,这在我看来,也是对内存的极大损伤之一。

Flink SQL

工作机制?

通过Calcite注册表对编写的 Sql 进行解析、验证、优化等操作。

① 在Table/SQL 编写完成后,通过Calcite 中的parse、validate、rel阶段,以及Blink额外添加的convert阶段, 将其先转为Operation;

② 通过Blink Planner 的translateToRel、optimize、translateToExecNodeGraph和translateToPlan四个阶段,将Operation转换成DataStream API的 Transformation;

③ 再经过StreamJraph -> JobGraph -> ExecutionGraph等一系列流程,SQL最终被提交到集群。

FlinkSQL怎么对SQL语句进行优化的?

会使用两个优化器: RBO(基于规则的优化器) 和 CBO(基于代价的优化器)

① RBO(基于规则的优化器)会将原有表达式裁剪掉,遍历一系列规则(Rule),只要满足条件就转换,生成最终的执行计划。一些常见的规则包括分区裁剪(Partition Prune)、列裁剪、谓词下推(Predicate Pushdown)、投影下推(Projection Pushdown)、聚合下推、limit下推、sort下推、常量折叠(Constant Folding)、子查询内联转join等;

② CBO(基于代价的优化器)会将原有表达式保留,基于统计信息和代价模型,尝试探索生成等价关系表达式,最终取代价最小的执行计划。CBO的实现有两种模型,Volcano模型,Cascades模型。这两种模型思想很是相似,不同点在于Cascades模型一边遍历SQL逻辑树,一边优化,从而进一步裁剪掉一些执行计划。

公司怎么提交的实时任务,有多少Job Manager? 有多少TaskManager?

1)我们使用yarn per-job模式提交任务;

2)集群默认只有一个 Job Manager。但为了防止单点故障,我们配置了高可用。对于standlone模式,我们公司一般配置一个主Job Manager,两个备用 Job Manager,然后结合 ZooKeeper 的使用,来达到高可用;对于yarn模式,yarn在Job Mananger故障会自动进行重启,所以只需要一个,我们配置的最大重启次数是10次;

3)基于yarn,动态申请TaskManager的数量。

Flink的keyby怎么实现的分区?分区、分组的区别是什么?

Keyby实现原理:
    对指定的key调用自身的hashCode方法=》hash1
    调用murmruhash算法,进行第二次hash =》键组ID
    通过一个公式,计算出当前数据应该去往哪个下游分区:
        键组id * 下游算子并行度 / 最大并行度(默认128)
分区:算子的一个并行实例可以理解成一个分区,是物理上的资源
分组:数据根据key进行区分,是一个逻辑上的划分
一个分区可以有多个分组,同一个分组的数据肯定在同一个分区

对于公司实时框架如何选择

① 需要关注流数据是否需要进行'状态管理';

② At-least-once或者Exectly-once消息投递模式是否有特殊要求;

③ 对于小型独立的项目,并且需要低延迟的场景,建议使用storm;

④ 如果你的项目已经使用了spark,并且秒级别的实时处理可以满足需求的话,建议使用sparkStreaming;

⑤ 要求消息投递语义为Exactly-Once的场景;数据量较大,要求高吞吐低延迟的场景;需要进行状态管理或窗口统计的场景,建议使用flink。

Logo

为开发者提供学习成长、分享交流、生态实践、资源工具等服务,帮助开发者快速成长。

更多推荐