大数据培训 Flink 基础知识分享
1、什么是 Flink?简单描述下
Flink 是一个以 流 为核心的高可用、高性能的分布式计算引擎。具备 流批一体,高吞吐、低延迟,容错能力,大规模复杂计算等特点,在数据流上提供 数据分发、通信等功能。
2、解释下其中的 数据流、流批一体、容错能力等概念?
数据流:所有产生的 数据 都天然带有 时间概念,把 事件 按照时间顺序排列起来,就形成了一个事件流,也被称作数据流。
流批一体:
首先必须先明白什么是 有界数据 和 无界数据
有界数据,就是在一个确定的时间范围内的数据流,有开始,有结束,一旦确定就不会再改变,一般 批处理 用来处理有界数据,如上图的 bounded stream。
无界数据,就是持续产生的数据流,数据是无限的,有开始,无结束,一般 流处理 用来处理无界数据。如图 unbounded stream。
Flink 的设计思想是以 流 为核心,批是流的特例,擅长处理 无界 和 有界 数据, Flink 提供 精确的时间控制能力 和 有状态 计算机制,可以轻松应对无界数据流,同时 提供 窗口 处理有界数据流。所以被成为流批一体。
容错能力:
在分布式系统中,硬件故障、进程异常、应用异常、网络故障等异常无处不在,Flink 引擎必须保证故障发生后 不仅可以 重启 应用程序,还要 确保 其内部状态保持一致,从最后一次正确的时间点重新出发
Flink 提供 集群级容错 和 应用级容错能力
集群级容错:Flink 与 集群管理器紧密连接,如 YARN、Kubernetes,当进程挂掉后,自动重启新进程接管之前的工作。同时具备 高可用性 ,可消除所有单点故障,
应用级容错:Flink 使用 轻量级分布式快照,设计检查点(checkpoint)实现可靠容错。
Flink 利用检查点特性,在框架层面 提供 Exactly-once 语义,即端到端的一致性,确保数据仅处理一次,不会重复也不会丢失,即使出现故障,也能保证数据只写一次_大数据培训。
3、Flink 和 Spark Streaming 的区别?
Flink 和 Spark Sreaming 最大的区别在于:
Flink 是标准的实时处理引擎,基于事件驱动,以流为核心,
Spark Streaming 的 RDD 实际是一组小批次的 RDD 集合,是微批(Micro-Batch)的模型,以批为核心。
下面我们介绍两个框架的主要区别:
1、架构模型
Spark Streaming 在运行时的主要角色包括:
服务架构集群和资源管理 Master / Yarn Application Master;
工作节点 Work / Node Manager;
任务调度器 Driver;任务执行器 Executor
Flink 在运行时主要包含:客户端 Client、作业管理 Jobmanager、任务管理 Taskmanager。
2、任务调度
Spark Streaming 连续不断的生成微小的数据批次,构建有向无环图 DAG,Spark Streaming 会依次创建 DStreamGraph、JobScheduler。
Flink 根据用户提交的代码生成 StreamGraph,经过优化生成 JobGraph,然后提交给 JobManager 进行处理,JobManager 会根据 JobGraph 生成 ExecutionGraph,ExecutionGraph 是 Flink 调度最核心的数据结构,JobManager 根据 ExecutionGraph 对 Job 进行调度,根据物理执行图部署到 Taskmanager 上形成具体的 Task 执行。
3、时间机制
Spark Streaming 支持的时间机制有限,只支持处理时间。
Flink 支持了流处理程序在时间上的三个定义:事件时间 EventTime、摄入时间 IngestionTime 、处理时间 ProcessingTime。同时也支持 watermark 机制来处理滞后数据。
4、容错机制
对于 Spark Streaming 任务,我们可以设置 checkpoint,然后假如发生故障并重启,我们可以从上次 checkpoint 之处恢复,但是这个行为只能使得数据不丢失,可能会重复处理,不能做到恰好一次处理语义。
Flink 则使用两阶段提交协议来解决这个问题。
4、Flink 的架构包含哪些?
Flink 架构分为 技术架构 和 运行架构 两部分。
1、技术架构
如下图为 Flink 技术架构:
Flink 作为流批一体的分布式计算引擎,必须提供面向开发人员的 API 层,同时还需要跟外部数据存储进行交互,需要连接器,作业开发、测试完毕后,需要提交集群执行,需要部署层,同时还需要运维人员能够管理和监控,还提供图计算、机器学习、SQL 等,需要应用框架层。
2、运行架构
如下图为 Flink 运行架构:
Flink 集群采取 Master-Slave 架构,Master 的角色为 JobManager,负责集群和作业管理,Slave 的角色是 TaskManager,负责执行计算任务,同时,Flink 提供客户端 Client 来管理集群和提交任务,JobManager 和 TaskManager 是集群的进程。
(1)Client
Flink 客户端是 Flink 提供的 CLI 命令行工具,用来提交 Flink 作业到 Flink 集群,在客户端中负责 StreamGraph (流图)和 JobGraph (作业图)的构建。
(2)JobManager
JobManager 根据并行度将 Flink 客户端提交的 Flink 应用分解为子任务,从资源管理器 ResourceManager 申请所需的计算资源,资源具备之后,开始分发任务到 TaskManager 执行 Task,并负责应用容错,跟踪作业的执行状态,发现异常则恢复作业等。
(3)TaskManager
TaskManager 接收 JobManage 分发的子任务,根据自身的资源情况 管理子任务的启动、 停止、销毁、异常恢复等生命周期阶段。Flink 程序中必须有一个 TaskManager。
5、Flink 的并行度是什么,介绍一下?
Flink 程序在执行的时候,会被映射成一个 Streaming Dataflow。一个 Streaming Dataflow 是由一组 Stream 和 Transformation Operator 组成的。在启动时从一个或多个 Source Operator 开始,结束于一个或多个 Sink Operator。
Flink 程序本质上是并行的和分布式的,在执行过程中,一个流(stream)包含一个或多个流分区,而每一个 operator 包含一个或多个 operator 子任务。操作子任务间彼此独立,在不同的线程中执行,甚至是在不同的机器或不同的容器上。
operator 子任务的数量是这一特定 operator 的并行度。相同程序中的不同 operator 有不同级别的并行度。
一个 Stream 可以被分成多个 Stream 的分区,也就是 Stream Partition。一个 Operator 也可以被分为多个 Operator Subtask。
如上图中,Source 被分成 Source1 和 Source2,它们分别为 Source 的 Operator Subtask。每一个 Operator Subtask 都是在不同的线程当中独立执行的。一个 Operator 的并行度,就等于 Operator Subtask 的个数。
上图 Source 的并行度为 2。而一个 Stream 的并行度就等于它生成的 Operator 的并行度。数据在两个 operator 之间传递的时候有两种模式:
(1)One to One 模式:两个 operator 用此模式传递的时候,会保持数据的分区数和数据的排序;如上图中的 Source1 到 Map1,它就保留的 Source 的分区特性,以及分区元素处理的有序性。
(2)Redistributing (重新分配)模式:这种模式会改变数据的分区数;每个 operator subtask 会根据选择 transformation 把数据发送到不同的目标 subtasks,比如 keyBy()会通过 hashcode 重新分区,broadcast()和 rebalance()方法会随机重新分区;
6、Flink 的并行度的怎么设置的?
在实际生产环境中可以从四个不同层面设置并行度:
操作算子层面(Operator Level)
执行环境层面(Execution Environment Level)
客户端层面(Client Level)
系统层面(System Level)
需要注意的优先级:算子层面 > 环境层面 > 客户端层面 > 系统层面。
7、Flink 编程模型了解吗?
Flink 应用程序主要由三部分组成,源 Source、转换 transformation、目的地 sink。这些流式 dataflows 形成了有向图,以一个或多个源(source)开始,并以一个或多个目的地(sink)结束。
8、Flink 作业中的 DataStream,Transformation 介绍一下?
Flink 作业中,包含两个基本的块:数据流(DataStream)和 转换(Transformation)。
DataStream 是逻辑概念,为开发者提供 API 接口,Transformation 是处理行为的抽象,包含了数据的读取、计算、写出。所以 Flink 作业中的 DataStream API 调用,实际上构建了多个由 Transformation 组成的数据处理流水线(Pipeline)
DataStream API 和 Transformation 的转换如下图:
9、Flink 的分区策略了解吗?
目前 Flink 支持 8 种分区策略的实现,数据分区体系如下图:
(1)GlobalPartitioner
数据会被分发到下游算子的第一个实例中进行处理。
(2)ForwardPartitioner
在 API 层面上 ForwardPartitioner 应用在 DataStream 上,生成一个新的 DataStream。
该 Partitioner 比较特殊,用于在同一个 OperatorChain 中上下游算子之间的数据转发,实际上数据是直接传递给下游的,要求上下游并行度一样。
(3)ShufflePartitioner
随机的将元素进行分区,可以确保下游的 Task 能够均匀地获得数据,使用代码如下:
dataStream.shuffle();
1
(4)RebalancePartitioner
以 Round-robin 的方式为每个元素分配分区,确保下游的 Task 可以均匀地获得数据,避免数据倾斜。使用代码如下:
dataStream.rebalance();
1
(5)RescalePartitioner
根据上下游 Task 的数量进行分区, 使用 Round-robin 选择下游的一个 Task 进行数据分区,如上游有 2 个 Source.,下游有 6 个 Map,那么每个 Source 会分配 3 个固定的下游 Map,不会向未分配给自己的分区写人数据。这一点与 ShufflePartitioner 和 RebalancePartitioner 不同, 后两者会写入下游所有的分区。
运行代码如下:
dataStream.rescale();
1
(6)BroadcastPartitioner
将该记录广播给所有分区,即有 N 个分区,就把数据复制 N 份,每个分区 1 份,其使用代码如下:
dataStream.broadcast();
1
(7)KeyGroupStreamPartitioner
在 API 层面上,KeyGroupStreamPartitioner 应用在 KeyedStream 上,生成一个新的 KeyedStream。
KeyedStream 根据 keyGroup 索引编号进行分区,会将数据按 Key 的 Hash 值输出到下游算子实例中。该分区器不是提供给用户来用的。
KeyedStream 在构造 Transformation 的时候默认使用 KeyedGroup 分区形式,从而在底层上支持作业 Rescale 功能。
(8)CustomPartitionerWrapper
用户自定义分区器。需要用户自己实现 Partitioner 接口,来定义自己的分区逻辑。
10、描述一下 Flink wordcount 执行包含的步骤有哪些?
主要包含以下几步:
(1)获取运行环境 StreamExecutionEnvironment
(2)接入 source 源
(3)执行转换操作,如 map()、flatmap()、keyby()、sum()
(4)输出 sink 源,如 print()
(5)执行 execute
提供一个示例:
11、Flink 常用的算子有哪些?
分两部分:
(1)数据读取,这是 Flink 流计算应用的起点,常用算子有:
从内存读:fromElements,从文件读:readTextFile,Socket 接入 :socketTextStream,也可以自定义读取:addSource,主要是从 kafka 获取数据
(2)处理数据的算子,主要用于 转换 过程
常用的算子包括:Map(单输入单输出)、FlatMap(单输入、多输出)、Filter(过滤)、KeyBy(分组)、Reduce(聚合)、Window(窗口)、Connect(连接)、Split(分割)等。
12、Flink 如何计算实时的 topN?
Flink 要实现 TopN 功能,主要做如下操作:
Flink 接收 kafka 数据源;
基于 EventTime 处理,指定 Watermark,这里调用 DataStream 的 assignTimestampsAndWatermarks 方法,抽取时间和设置 watermark。
将 kafka 的 json 格式数据转为实体类对象。
根据用户 Username 进行分组,对于实时统计 TopN 可以使用滑动窗口。设置窗口长度取 10s,每次滑动(slide)5s,即 5 秒钟更新一次过去 10s 的排名数据。
.keyBy("username")
.timeWindow(Time.seconds(10), Time.seconds(5))
.aggregate(new CountAgg(), new WindowResultFunction())
使用 .aggregate(AggregateFunction af, WindowFunction wf) 做增量的聚合操作,它能用 AggregateFunction 提前聚合掉数据,减少 state 的存储压力。
CountAgg 实现了 AggregateFunction 接口,功能是统计窗口中的条数,即遇到一条数据就加一。
WindowFunction 将每个 key 每个窗口聚合后的结果带上其他信息进行输出。这里实现的 WindowResultFunction 将用户名,窗口,访问量封装成了 UserViewCount 进行输出。
为了统计每个窗口下活跃的用户,我们需要再次按窗口进行分组,根据 UserViewCount 中的 windowEnd 进行 keyBy() 操作。然后使用 ProcessFunction 实现一个自定义的 TopN 函数 TopNHotItems 来计算点击量排名前 3 名的用户,并将排名结果格式化成字符串,便于后续输出。
.keyBy("windowEnd")
.process(new TopNHotUsers(3))
.print();
ProcessFunction 是 Flink 提供的一个 low-level API,它主要提供定时器 timer 的功能。通过 timer 来判断何时收齐了某个 window 下所有用户的访问数据。由于 Watermark 的进度是全局的,在 processElement 方法中,每当收到一条数据 ItemViewCount,就注册一个 windowEnd+1 的定时器 windowEnd+1 的定时器被触发时,意味着收到了 windowEnd+1 的 Watermark,即收齐了该 windowEnd 下的所有用户窗口统计值。然后使用 onTimer() 将收集的所有商品及点击量进行排序,选出 TopN,并将排名信息格式化成字符串后进行输出。
使用 ListState 来存储收到的每条 UserViewCount 消息,保证在发生故障时,状态数据的不丢失和一致性。ListState 是 Flink 提供的类似 Java List 接口的 State API,它集成了框架 checkpoint 机制,可以保证 exactly-once 的语义。
转载文章来源于数据仓库与 Python 大数据
评论