Flink 基础原理与优化思路

什么是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 的特性

  • 支持高吞吐、低延迟、高性能的流处理 支持带有事件时间的窗口 (Window) 操作
  • 支持有状态计算的 Exactly-once 语义
  • 支持高度灵活的窗口 (Window) 操作,支持基于 time、count、session 以及 datadriven 的窗口操作
  • 支持具有 Backpressure 功能的持续流模型 支持基于轻量级分布式快照(Snapshot)实现的容错 一个运行时同时支持 Batch on Streaming 处理和 Streaming 处理 Flink 在 JVM 内部实现了自己的内存管理
  • 支持迭代计算
  • 支持程序自动优化:避免特定情况下 Shuffle、排序等昂贵操作,中间结果有必要进行缓存

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

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

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

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

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

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

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。

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

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

Flink 的常用算子?

Flink 最常用的常用算子包括:

  • Map:DataStream → DataStream,输入一个参数产生一个参数,map 的功能是对输入的参数进行转换操作。
  • Filter:过滤掉指定条件的数据。
  • KeyBy: 按照指定的 key 进行分组。
  • Reduce:用来进行结果汇总合并。
  • Window:窗口函数,根据某些特性将每个 key 的数据进行分组

Flink 分区策略?

分区策略是用来决定数据如何发送至下游。 目前 Flink 支持了 8 中分区策略的实现。
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 接口,来定义自己的分区逻辑

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

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

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

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

Flink1.9 的新特性?

支持 hive 读写,支持 UDF
Flink SQL TopN 和 GroupBy 等优化
Checkpoint 跟 savepoint 针对实际业务场景做了优化
Flink state 查询

消费 kafka 数据的时候,如何处理脏数据?

可以在处理前加一个 fliter 算子,将不符合规则的数据过滤出去。

Flink 任务延迟高,想解决这个问题,你会如何入手?

在 Flink 的后台任务管理中,我们可以看到 Flink 的哪个算子和 task 出现 了反压。最主要的手段是资源调优和算子调优。资源调优即是对作业中的Operator 的并发数( parallelism)、CPU(core)、堆内存(heap_memory)等参数进行调优。作业参数调优包括:并行度的设置,State 的设置, checkpoint 的设置

Flink 的反压和 Strom 有哪些不同?

Storm 是通过监控 Bolt 中的接收队列负载情况, 如果超过高水位值就会将反压信息写到 Zookeeper , Zookeeper 上的 watch 会通知该拓扑的所有 Worker 都进入反压状态,最后 Spout 停止发送 tuple。
Flink 中的反压使用了高效有界的分布式阻塞队列,下游消费变慢会导致发送 端阻塞。
二者最大的区别是 Flink 是逐级反压, 而 Storm 是直接从源头降速。

Flink 中的 Window 出现了数据倾斜,你有什么解决办法?

window 产生数据倾斜指的是数据在不同的窗口内堆积的数据量相差过多。本质上产生这种情况的原因是数据源头发送的数据量速度不同导致的。出现这种情况一般通过两种方式来解决:

  • 在数据进入窗口前做预聚合
  • 重新设计窗口聚合的 key

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

Flink 通过实现两阶段提交和状态保存来实现端到端的一致性语义。 分为以下
几个步骤:
开始事务(beginTransaction)创建一个临时文件夹,来写把数据写入到这个文件夹里面
预提交( preCommit)将内存中缓存的数据写入文件并关闭
正式提交(commit)将之前写完的临时文件放入目标目录下。这代表着最终的数据会有一些延迟
丢弃( abort)丢弃临时文件 若失败发生在预提交成功后,正式提交前。可以根据状态来提交预提交的数据,也可删除预提交的数据

Flink Job 的提交流程

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

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 中的资源以供下一次提交任务使用

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

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

  • 一个 Flink 任务的 DAG 生成计算图大致经历以下三个过程:StreamGraph 最接近代码所表达的逻辑层面的计算拓扑结构,按照用户代码的执行顺序向 StreamExecutionEnvironment 添加StreamTransformation 构成流式图。
  • JobGraph 从 StreamGraph 生成,将可以串联合并的节点进行合并,设置节点 之间的边,安排资源共享 slot 槽位和放置相关联的节点, 上传任务所需的文件, 设置检查点配置等。相当于经过部分初始化和优化处理的任务图。
  • ExecutionGraph 由 JobGraph 转换而来,包含了任务具体执行所需的内容, 是最贴近底层实现的执行图。

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

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

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

Flink 将 SQL 校验、 SQL 解析以及 SQL 优化交给了 Apache Calcite。Calcite 在其他很多开源项目里也都应用到了,譬如 Apache Hive, Apache Drill, Apache Kylin, Cascading。Calcite 在新的架构中处于核心的地位,
在这里插入图片描述
构建抽象语法树的事情交给了 Calcite 去做。 SQL query 会经过 Calcite 解析器转变成 SQL 节点树, 通过验证后构建成 Calcite 的抽象语法树(也就是图中的Logical Plan)。另一边,Table API 上的调用会构建成 Table API 的抽象语法树,并通过 Calcite 提供的 RelBuilder 转变成 Calcite 的抽象语法树。然后依次 被转换成逻辑执行计划和物理执行计划。
在提交任务后会分发到各个 TaskManager 中运行, 在运行时会使用 Janino编译器编译代码后运行

说说 Flink 中的状态存储?

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

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值