这里目录标题
1.简介
1.1. 大数据计算引擎
- 第一代: MapReducer
- 批处理:Mapper, Reducer
- Hadoop的MapReducer将计算分为两个阶段, 分别为Map和Reducer. 对于上层应用来说, 就 不得不想方设法去拆分算法, 甚至于不得不在上层应用实现多个Job的串联, 以完成一个完整的 算法, 例如迭代计算.
- 第二代: DAG框架 (Tez) + MapReducer
- 批处理 1个Tez = MR (1) + MR (2) + … + MR (n) 相比MR效率有所提升
- 第三代: Spark
- 批处理, 流处理, SQL高层API支持 自带DAG 内存迭代计算, 性能较之前大幅提升
- 第四代: Flink
- 批处理, 流处理, SQL高层API支持 自带DAG 流式计算性能更高, 可靠性更高
1.2、Flink 特点
Flink不仅是一个高吞吐、低延迟的计算引擎,同时还 提供很多高级的功能。比如它提供了有状态的计算,支持状态管理,支持强一致性的数据语义以及 支持 基于Event Time的WaterMark对延迟或乱序的数据进行处理等。
- Flink 项目的理念是:“Apache Flink 是为分布式、高性能、随时可用以及准确的流处理应用程序打造的开源流处理框架”。
- Apache Flink 是一个框架和分布式处理引擎,用于对无界和有界数据流进行有状态计算。Flink 被设计在所有常见的集群环境中运行,以内存执行速度和任意规模来执行计算。
- Flink流处理的特点
- 同时支持高吞吐,低延迟,高性能
- 低延迟,状态保存在内存中,很快计算完。
- 事件驱动(Event-driven)。
- 支持事件时间(Event Time)
- 概念 Process TIme,大多数框架窗口计算采用的都是系统时间(process time),也是事件传输到计算框架处理时,系统主机的当前时间。
- Event Time,Flink支持基于事件时间(Event Time)语义进行窗口计算,也就是使用事件产生的时间,这种基于事件驱动的机制使得事件即使乱序到达,流系统也能够计算出精确的结果,保持了事件原本产生时的时序性,尽可能避免网络传输或硬件系统的影响。
- 支持有状态计算
- 支持高度灵活的窗口(Window)操作。
- Flink中除了滚动窗口,滑动窗口还有基于数量的窗口Count,基于会话的窗口Session。
- 基于轻量级的分布式快照(CheckPoint)来实现容错
- Save Point保存点;CheckPoint是自动的,做容错。Save Point是手动的,处理程序升级。
- 基于JVM实现独立的内存管理
- 同时支持高吞吐,低延迟,高性能
1.3、流处理框架对比
- Flink是一行一行处理,而SparkStream是基于数据片集合(RDD)进行小批量处理,所以Spark在流式处理方面,不可避免增加一些延时。
- Flink的流式计算跟Storm性能差不多,支持毫秒级计算,而Spark则只能支持秒级计算。
- Spark和Flink全部都运行在Hadoop Yarn上, 性能为Flink > Spark > Hadoop (MR) , 迭代次数越多越明显.
- 性能上, Flink优于Spark和Hadoop最主要的原因是Flink支持增量迭代, 具有对迭代自动优化的功能.
1.4、事件驱动型
事件驱动型应用是一类具有状态的应用,它从一个或多个事件数据流中读取事件,并根据到来的事件做出反应,包括触发计算、状态更新或其他外部动作等。事件驱动型应用是在传统的应用设计基础上进化而来的。
在传统的设计中,通常都具有独立的计算和数据存储层,应用会从一个远程的事务数据库中读写数据。而事务驱动型应用,数据和计算是放在一起的,应用只需访问本地(内存或磁盘)即可获取数据。
系统容错性是通过定期向远程持久化存储写入检查点来实现的。
典型的事件驱动型应用包括反欺诈、异常检测、基于规则的报警、业务流程监控、Web 应用(社交网络)等。
- (2)事件驱动型应用的优势
- 访问本地数据,吞吐量方面,还是在延迟方面,都可以获得更好的性能。
- 持久化存储周期性地写入检查点,可以采用异步和增量的方式来实现。对于常规的事件处理的影响是很小的。
- (3)Flink是如何支持事件驱动型应用的
- Flink提供了丰富的状态操作原语,管理大量的数据,确保“精确一次”的一致性。
- Flink还支持事件时间、高度可定制的窗口逻辑和细粒度的时间控制,
- 拥有一个复杂事件处理(CEP)类库,可以用来检测数据流中的模式。
- “保存点”(savepoint)。保存点是一个一致性的状态镜像。
1.5、Flink 技术栈
1.6、Flink 编程模型
Flink 提供了不同级别的抽象(如图所示),以开发流或批处理作业。
- 越顶层越抽象,表达含义越简明,使用越方便
- 越底层越具体,表达能力越丰富,使用越灵活
- SQL&Table API:
- SQL 构建在Table 之上,都需要构建Table 环境。
- 不同的类型的Table 构建不同的Table 环境中。
- Table 可以与DataStream或者DataSet进行相互转换。
- Streaming SQL不同于存储的SQL,最终会转化为流式执行计划
- DataStream DataSet API
- ProcessFunction多了一些算子。
- DataStream API为许多通用的流处理操作提供了原语。
- DataSet API 是批处理API,处理有限的数据集。
- DataStream API是流处理API,处理无限的数据集。
- Stateful Stream Processing
- ProcessFunction是Flink最底层的接口。
- ProcessFunction可以处理一或者两条输入数据流中的单个事件或者归入一个特定窗口内的多 个事件。
- 它提供了对时间和状态的细粒度控制。
- 虽然灵活性高,但开发比较复杂,需要具备一定的编码能力。
- 扩展库:
- 复杂事件处理CEP,Gelly做图计算的,是一个可扩展的图形处理和分析库。
2、Flink 搭建
Flink 1.9.3 搭建:
https://blog.csdn.net/weixin_43660536/article/details/120089661.
3、Flink 运行架构
3.1、运行组件
-
Flink运行时架构主要包括四个不同的组件,它们会在运行流处理应用程序时协同工作:
- 作业管理器(JobManager)
- 资源管理器(ResourceManager)
- 任务管理器(TaskManager)
- 分发器(Dispatcher)
-
Flink是用Java和Scala实现的,所以所有组件都会运行在Java虚拟机(JVMs)上。
-
Dispatcher 分发器
- 分发器可以跨作业运行,它为应用提交提供了REST接口。
- 用于接受客户端的请求,并将应用移交给一个作业管理器。
- 也会启动一个Web UI,用来方便地展示和监控作业执行的信息。
-
JobManager 作业管理器
- 作业管理器是控制一个应用程序执行的主进程。
- 管理任务,向资源管理器(ResourceManager)申请资源(Slot 插槽)。
- 作业管理器会把JobGraph转换成一个物理层面的数据流图,这个图被叫做“执行图”(ExecutionGraph),包含了所有可以并发执行的任务。
- 会将执行图分发到真正运行 它们的TaskManager上。
-
ResourceManager 资源管理器
- 要负责管理任务管理器(TaskManager)的插槽(slot),TaskManger插槽slot是Flink 中定义的处理资源单元。
- 将有空闲插槽的TaskManager分配给JobManager 。
- 负责终止空闲的TaskManager,释放计算资源。
-
TaskManager 任务管理器
- 任务管理器是Flink中的工作进程,具体任务的执行者。
- 每一个TaskManager都包含了一定数量的插槽 (slots)。slot的数量限制了TaskManager能够执行的任务数量。
- 收到资源管理器的指令后,TaskManager就会将一个或者多个插槽提供给作业管理器调用。
3.2、Job任务提交
- Flink是用Java和Scala实现的,所以所有组件都会运行在Java虚拟机(JVMs)上。
- 当 Flink 集群启动后,首先会启动一个 JobManger 和一个或多个的 TaskManager。然后启动了ResourceManager和Dispatcher 。
- 由 Client 提交任务给 Dispatcher ,
- Dispatcher 将任务移交给一个作业管理器JobManager;
- JobManager 会向资源管理器(ResourceManager)请求执行任务必要的资源,
- ResourceManager启动后,TaskManager 会向资源管理器注册它的插槽;
- ResourceManager 会将有空闲插槽的 TaskManager 分配给 JobManager。
- 收到ResourceManager的指令后, TaskManager 就会将一个或者多个插槽提供给 JobManager 调用。
- JobManager 再调度任务到各个 TaskManager 去执行,
- 然后 TaskManager 将心跳和统计信息汇报给 JobManager。TaskManager 之间以流的形式进行数据的传输。
- 上述均为独 立的 JVM 进程。
上图是从一个较为高层级的视角,来看应用中各组件的交互协作。
如果部署的集群环境不同(例如 YARN,Mesos,Kubernetes,standalone 等),其中一些步骤可以被省略,或是有些组件会运行在同一个 JVM 进程中。
具体地,如果我们将 Flink 集群部署到 YARN 上,那么就会有如下的提交流程:
- 步骤1:当启动一个新的 Flink YARN Client会话,客户端首先会检查所请求的资源(容器和内存) 是否可用。之后,它会上传包含了 Flink 配置文件和 jar包到 HDFS.
- 步骤2:客户端的请求一个container资源去启动 ApplicationMaster 进程
- 步骤3:ResourceManager选一台NodeManager机器启动AM。
- 注意1:在这过程中,因为客户端已经将配置文件和jar包作为容器的资源注册了,所以 NodeManager 会负责准备容器做一些初始化工作(例如,下载文件)。一旦这些完成了, ApplicationMaster (AM) 就启动了。
- 注意2:JobManager 和 AM 运行在同一个容器中。一旦它们成功地启动了,AM 知道 JobManager 的地址(它自己)。它会为 TaskManager 生成一个新的 Flink 配置文件(这样 它们才能连上 JobManager)。该文件也同样会上传到 HDFS。另外,AM 容器同时提供了 Flink 的 Web 界面服务。
- 步骤4:AM 开始为 Flink 的 TaskManager 分配容器(container),在对应的nodemanager上面启 动taskmanager.
- 步骤5: 初始化工作,从 HDFS 下载 jar 文件和修改过的配置文件。一旦这些步骤完成了,Flink 就安 装完成并准备接受任务了。
3.3、任务调度
3.3.1、执行图 ExecutionGraph
-
查看执行图 http://flink.apache.org/visualizer/
-
Flink 中的执行图可以分成四层:StreamGraph -> JobGraph -> ExecutionGraph -> 物理执行图。
-
- StreamGraph:
- 是根据用户通过 Stream API 编写的代码生成的最初的图。用来 表示程序的拓扑结构。
- JobGraph:
- StreamGraph经过优化后生成了 JobGraph,提交给 JobManager 的数据结构。
- 主要的优化为,将多个符合条件的节点 chain 在一起作为一个节点
- ExecutionGraph:
- JobManager 根据 JobGraph 生成ExecutionGraph。
- ExecutionGraph是JobGraph的并行化版本,是调度层最核心的数据结构。
- 物理执行图:
- JobManager 根据 ExecutionGraph 对 Job 进行调度后,在各个TaskManager 上部署 Task 后形成的“图”,
- 并不是一个具体的数据结构。
3.3.2、数据并行与任务并行
- 可以以不同方式利用数据流图中的并行性。
- 第一,我们可以对输入数据进行分区,并在数据的子集上并行执行具有相同算子的任务并行。这种类型的并行性被称为数据并行性。数据并行是有用的,因为它允许处理大量数据,并将计算分散到 不同的计算节点上。
- 第二,我们可以将不同的算子在相同或不同的数据上并行执行,这种并行性称为任务并行性。使用 任务并行性,我们可以更好地利用计算资源。
3.3.3、TaskManager 和 Slots
-
一个TaskManager可以同时执行多个任务(tasks)。
- 这些任务可以是同一个算子的子任务(数据并行)
- 这些任务可以是来自不同算子(任务并行)
- 这些任务可以是另一个不同应用程序(作业并行)。
-
TaskManager提供了一定数量的处理插槽(processing slots),用于控制并行执行的任务数。
-
TaskManager 在启动的时候就设置好了槽位数(Slot),每个 slot 能启动一个 Task,Task 为线程。
-
考虑到Slot分组,所以实际运行Job时所需的Slot总数 = 每个Slot组中的最大并行度。
-
Slot对资源的隔离仅仅是对内存进行隔离,策略是均分。
-
插槽的数量通常与每个TaskManager的可用CPU内核数成比例。一般情况下slot数是你的cpu核数;
-
JobGraph
包含了5个算子——它是应用程序的非并行表示。
其中算子A和C是数据源(source),E是输出端(sink)。C和E并行度为2,而其他的算子并行度为4。因为最高的并行度是4,所以应用需要至少四个slot来执行任务。
作业管理器将JobGraph转化为“执行图”(ExecutionGraph),并将任务分 配到四个可用的slot上。对于有4个并行任务的算子,它的task会分配到每个slot上。
可以让多个tasks跑在同一个TaskManager内,也就可以是的tasks之间 的数据交换更高效。
Task Slot 是静态的概念,是指TaskManager具有的并发执行能力,可以通过参数 taskmanager.numberOfTaskSlots 进行配置;而并行度 parallelism 是动态概念, 即TaskManager运行程序时实际使用的并发能力,可以通过参数 parallelism.default 进行配置。
3.3.4、并行度(Parallelism)
- Flink 程序的执行具有并行、分布式的特性。
- 在执行期间,流具有一个或多个流分区,并且每个operator具有一个或多个operator子任务。
- 一个特定算子的子任务(subtask)的个数被称之为其并行度(parallelism)。
- 一 个程序中,不同的算子可能具有不同的并行度。
- 一般情况下,一个流程序的并行度,可以认为就是其所有算子中最大的并行度。
3.3.4. 任务并行度设置
Flink程序的任务并行度设置分为四个级别。
- 算子级别—调用其setParallelism()方法来定义单个运算符的并行度 。
- 执行环境级别
- 客户端级别
- 系统级别
3.3.5、任务链 Operator Chains
- 相同并行度的 one to one 操作,Flink 这样相连的算子链接在一起形成一个 task, 原来的算子成为里面的一部分。
- 相当于Spark里面的管道(pipeline)。
- 它能减少线 程之间的切换和基于缓存区的数据交换,在减少时延的同时提升吞吐量。
- 链接的行为可以在编程API中进行指定开启操作链(默认) 和 禁用操作链的
// 关闭操作链..
env.disableOperatorChaining();
// 还可以控制更细粒度的任务链,比如指明从哪个operator开始形成一条新的链
someStream.map(...).startNewChain();
//但不能使用someStream.startNewChain()。
4、程序与数据流(DataFlow)
4.1、程序
- Flink上运行的程序会被映射成 “ 逻辑数据流 ”(dataflows),
- Flink程序都是由三部分组成的: Source 、Transformation 和 Sink。
- 在大部分情况下,程序中的转换运算(transformations)跟dataflow中的算子 (operator)是一一对应的关系。
4.2、dataFlow 数据流
-
数据流是一个可能无限的事件序列。
-
Flink程序映射到流数据上,由流和转换运算符组成。
-
每一个dataflow以一个或多个sources开始以一个或多个sinks结束。
-
数据流程序描述了数据如何在算子之间流动。数据流程序通常表示为有向图,其中节点称为算子, 用来表示计算,边表示数据之间的依赖性。
-
算子是数据流程序的基本功能单元。
-
数据流图被称为逻辑流图,因为它们表示了计算逻辑的高级视图。为了执行一个数据流程序, Flink会将逻辑流图转换为物理数据流图,详细说明程序的执行方式。
4.3、数据传输形式
-
一个程序中,不同的算子可能具有不同的并行度
-
one-to-one (forwarding) 的模式也可以是 redistributing 的模式,取决于算子的种类 ;
-
One-to-one:stream维护着分区以及元素的顺序(比如source和map之间)
- 上游元素的个数以及顺序跟子任务生产的元素的个数、顺序相同。
- map、fliter、flatMap等算子都是one-to-one的 对应关系。
-
Redistributing:stream的分区会发生改变。
- 每一个算子的子任务依据所选择的 transformation发送数据到不同的目标任务。
- redistribute 过程就类似于 Spark 中的 shuffle 过程。
- keyBy 基于 hashCode 重分区、而 broadcast 和 rebalance 会随机重新分区。
4.4、数据交换策略
- 数据交换策略定义了在物理执行流图中如何将数据分配给任务
4.4.1. 前向策略
将数据从一个任务发送到一个接收任务。如果两个任务都位于同一台物理计算机上(这通常由任务调度 器确保),这种交换策略可以避免网络通信。
4.4.2. 广播策略
将所有数据发送到算子的所有的并行任务上面去。因为这种策略会复制数据和涉及网络通信,所以 代价相当昂贵。
4.4.3. 键控的策略
通过Key值(键)对数据进行分区保证具有相同Key的数据将由同一任务处理。
在图2-2中,输出 “Extract hashtags”算子使用键来分区(hashtag),以便count算子的任务可以正确计算每个#标 签的出现次数。
4.4.4. 随机策略
统一将数据分配到算子的任务中去,以便均匀地将负载分配到不同的计算任务。
4.5、延迟 和吞吐量
-
对于批处理程序,我们通常关心一个作业的总的执行时间,或我们的处理引擎读取输入所需的时间,
-
流处理程序必须尽可能快的提供输入数据的计算结果。我们使用延迟和吞吐量来表征流处理的性能要求。
-
延迟: 表示处理事件所需的时间。
- 它是接收事件和看到在输出中处理此事件的效果之间的时间间隔。
- 在数据流中,延迟是以时间为单位测量的,例如毫秒。
-
吞吐量:是衡量系统处理能力的指标,也就是处理速率。
4.6、DataFlow 的操作
- 流处理引擎通常提供一组内置操作:摄取(ingest),转换(transform)和输出流(output).
- 数据的状态
- 无状态:事件的处理不依赖于过去看到的任何事件,也没有保留历史。
- 有状态:有状态操作可能会维护之前收到的事件的信息。
4.6.2. 数据的摄取
- 数据摄取和数据出口操作允许流处理程序与外部系统通信。
- 数据摄取是操作从外部源获取原始数据并将其转换为其他格式(ETL)。
- 数据源可以从TCP Socket,文件,Kafka Topic或传感器数据接口中提取数据。
4.6.3. 数据的转换
- 转换算子是单遍处理算子,碰到一个事件处理一个事件。
- 这些操作在使用后会消费一个事件,然后对事件数据做一些转换,产生一个新的输出流。
- 转换逻辑可以集成在 操作符中或由UDF函数提供
4.6.4. 数据的滚动聚合
- 滚动聚合是一种聚合,例如sum,minimum和maximum,为每个输入事件不断更新。
- 聚合操作是有状态的,并将当前状态与传入事件一起计算以产生更新的聚合值。
- 能够有效地将当前状态与事件相结合产生单个值,聚合函数必须是关联的和可交换的。否则,操作符必须存储完整的流数据历史。
4.6.5. 数据的输出
- 数据出口是以适合消费的形式产出到外部系统。
- 执行数据出口的运算符称为数据接收器,包括文件,数据库,消息队列和监控接口。
4.7、四大基石
5、Flink 流处理API
- Flink 流处理 API 详解
https://blog.csdn.net/weixin_43660536/article/details/120142486.
6、Window 窗口机制
7、时间语义与watermark
- Flink Windows机制 + 时间语义与水位线watermark
- https://blog.csdn.net/weixin_43660536/article/details/120142618.
8、状态管理State
9、ProcessFunction API(底层API)
- Flink state状态 与 ProcessFunction API 详解
- https://blog.csdn.net/weixin_43660536/article/details/120142911.
10、容错机制CheckPoint
13、Flink 反压机制
- Flink 容错机制 与 反压机制 详解
- https://blog.csdn.net/weixin_43660536/article/details/120143143.