# flink1.17-summarize **Repository Path**: chen_shuai_jun/flink1.17-summarize ## Basic Information - **Project Name**: flink1.17-summarize - **Description**: No description available - **Primary Language**: Unknown - **License**: Not specified - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2024-03-06 - **Last Updated**: 2024-03-06 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # 本仓库是flink1.17学习的全部总结,包括了代码和概念的描述 ## 1、flink概述 ### 1.1 flink是什么 flink是一个分布式的数据处理引擎,主要用于有界流和无界流的计算。 ### 1.2 flink的特点 flink具有低延迟、高吞吐、精确性和容错性的特点 ### 1.3 flink和SparkStreaming的区别 | | flink | sparkStreaming | |--|--|--| | 计算模型 | 流式计算 | 微批 | | 窗口 | 多且灵活 | 少、不灵活 | | 状态 | 有 | 没有 | | 时间语义 | 事件时间、处理时间、注入时间 | 处理时间 | | 流式SQL | 有 | 没有 | ### 1.3 flink应用场景 大多数是用在实时计算的场景 ## 2、Flink的部署 ### 2.1 flink的集群角色 - JobManager:主要是负责资源的管理和作业的调度 - Dispatch: 作业的分发,启动JobMaster - ResourceManager :管理slot - SlotManager - JobMaster:作业的调度 - slot pool - TaskManager :主要负责计算 ### 2.2 部署模式 - local 测试使用 - standlone:flink自己管理资源,对于一个性能要求比较高的场景适用 - yarn:有yarn来管理资源 - session: 共享集群,提高资源的利用率,但是会出现资源争抢的情况。 - per-job: 独享集群,一个作业一个集群,作业提交的时候,创建集群 - application: 独享集群,一个作业一个集群,作业提交的时候,创建集群。和per-job的主要区别是,参数的解析、StreamGraph的生产jobGraph的生成是在JM中完成。 - k8s ## 3 Flink运行是架构 ### 3.1 任务提交的流程和核心的组件 ![输入图片说明](input/image.png) 1)作业管理器(JobManager JobManager是一个Flink集群中任务管理和调度的核心,是控制应用执行的主进程。也就是说,每个应用都应该被唯一的JobManager所控制执行。 JobManger又包含3个不同的组件。 **(1)JobMaster** JobMaster是JobManager中最核心的组件,负责处理单独的作业(Job)。所以JobMaster和具体的Job是一一对应的,多个Job可以同时运行在一个Flink集群中, 每个Job都有一个自己的JobMaster。需要注意在早期版本的Flink中,没有JobMaster的概念;而JobManager的概念范围较小,实际指的就是现在所说的JobMaster。 在作业提交时,JobMaster会先接收到要执行的应用。JobMaster会把JobGraph转换成一个物理层面的数据流图,这个图被叫作“执行图”(ExecutionGraph),它包含了所有可以并发执行的任务。JobMaster会向资源管理器(ResourceManager)发出请求,申请执行任务必要的资源。一旦它获取到了足够的资源,就会将执行图分发到真正运行它们的TaskManager上。 而在运行过程中,JobMaster会负责所有需要中央协调的操作,比如说检查点(checkpoints)的协调。 **(2)资源管理器(ResourceManager)** ResourceManager主要负责资源的分配和管理,在Flink 集群中只有一个。所谓“资源”,主要是指TaskManager的任务槽(task slots)。任务槽就是Flink集群中的资源调配单元,包含了机器用来执行计算的一组CPU和内存资源。每一个任务(Task)都需要分配到一个slot上执行。 这里注意要把Flink内置的ResourceManager和其他资源管理平台(比如YARN)的ResourceManager区分开。 **(3)分发器(Dispatcher)** Dispatcher主要负责提供一个REST接口,用来提交应用,并且负责为每一个新提交的作业启动一个新的JobMaster 组件。Dispatcher也会启动一个Web UI,用来方便地展示和监控作业执行的信息。Dispatcher在架构中并不是必需的,在不同的部署模式下可能会被忽略掉。 **2)任务管理器(TaskManager)** TaskManager是Flink中的工作进程,数据流的具体计算就是它来做的。Flink集群中必须至少有一个TaskManager;每一个TaskManager都包含了一定数量的任务槽(task slots)。Slot是资源调度的最小单位,slot的数量限制了TaskManager能够并行处理的任务数量。 启动之后,TaskManager会向资源管理器注册它的slots;收到资源管理器的指令后,TaskManager就会将一个或者多个槽位提供给JobMaster调用,JobMaster就可以分配任务来执行了。 在执行过程中,TaskManager可以缓冲数据,还可以跟其他运行同一应用的TaskManager交换数据。 ### 3.2 核心概念 1. 并行度 一个作业的并行度是等于整个作业的最大并行度。并行度的设置是有以下三个地方可以设置(优先级:低 ---> 高): (1)在配置文件中设置 (2)提交参数设置 (3)代码env (4)算子 2. 算子链 flink会将满足one-to-one并且并行度相同的算子合并到一起进行计算,这个过程就叫做Operator Chain 3. 任务槽 在flink中每一个TM就是一个JVM进程,因此每个TM可以启动多个线程进行任务的计算,启动的任务越多,每个任务能够分配的资源就越少。为了控制TM的并发量,需要对TM的资源进行划分,这就有了slot。slot就是对资源的划分,他划分的是内存,一个TM的最大并发能力就是这个TM的slot数量。 4. 任务槽和并行度的关系 slot的数量表示的是最大的并发能力,并行度指的是实际的并发能力。 ### 3.3 作业的提交流程 这里是以yarn-per-job的方式介绍flink任务的提交流程。 1. ClientFront解析参数 2. 生成对应的客户端 3. 执行main方法 4. 生成StreamGraph 5. 进行Operator Chain将StreamGraph转换成JobGraph 6. 封装提交参数 7. 提交作业到yarn的ResourceManager 8. yarn的ResourceManager到作业之后会找到一个NodeManager启动一个ApplicationManager(其实就是flink的JobManager)。 9. 启动DIspatch和flink的ResourceManager。 10. dispatch会为作业启动一个JobMaster 11. JobMaster会将作业图转换成为ExecutionGraph。 12. 根据任务运行所需要的资源,向flink的RM去申请资源。 13. 如果flink的RM有足够的资源,就直接给JM,如果没有就像yarn的RM申请。 14. yarn的RM会启动TM,然后TM会向flink的RM进行注册。 15. flink的RM会分配相应的slot执行任务。 16. JobMaster会分配对应的因为到slot中。 ## 4、DataStreamAPI ### 4.1 执行环境 1. 创建执行环境 - local **createLocalEnvironment**: 创建本地的执行环 - remote **createRemoteEnvironment** :创建远程的执行环境 - get **getExecutionEnvironment**:如果能够获得配置文件就创建远程的,如果获取不到就创建本地的。 2. 执行模式 - 流模式 - 批模式 ### 4.2 算子 1. source算子 (1) 基于文件的 - `readTextFile(path)` - `TextInputFormat` - `readFile(fileInputFormat, path)` - `readFile(fileInputFormat, path, watchType, interval, pathFilter, typeInfo)` (2)基于Socket的 - `socketTextStream` (3) 基于集合的 - `fromCollection(Collection)` (4) 自定义的 当前flink所支持的source有 ![输入图片说明](input/source.png.png) 2. 转化算子 - map - flatMap - filter - key - reduce - sum - min - minby:和min的主要的区别在于,他会更新掉非对比字段 - max - maxby - join - union:一次连接多条流类型必须是一样 - connect:一次连接一条流,类型可以不一样 - window:这里是key的window - Tumbing Window - Sliding Window - Session Window - Cumulate Window - Global Window 全局窗口分配器将具有相同关键字的所有元素分配给同一个全局窗口。只有当您还指定了自定义触发器时,此窗口方案才有用。否则,将不执行任何计算,因为全局窗口没有我们可以处理聚合元素的自然结束。 - windowAll:这个窗口是使用在DataStream上的。所有的数据会进入到一个分区。 - window join :将具有等值条件,并且中同一窗口的数据join起来 - 窗口计算函数: - reduce Function:增量聚合,来一条数据聚合一次。输入数据类型、累加器和输出数据的类型是相同的。 - aggregate Function:增量聚合,来一条数据聚合一次。输入数据类型、累加器和输出数据的类型可以完全不相同。 - process Function :全量计算的,数据攒齐了一起算,同时可以拿到窗口和上下文的数据。 3. sink算子 ![输入图片说明](input/sink.png.png) 4、分区算子 - keyby:使用的分区器是KeyedGropStreamPartitioner - rescale:使用的分区器是RescalePartitioner - rebalance:使用的分区器是RebalancePartitioner - global: 使用分分区器是GlobalPartitioner - shuffer:使用的分区器是shufferPartitioner 还有forwardPartitioner,这个是原始的分区器。 还有BroadcasePartitioner 5、算子链和solt相关的 startNewChain disableNewChain setSlotSharingGroup ## 4、时间和窗口 ### 4.1 窗口 1. 窗口的概念:flink是用于流式计算的,它主要计算的是无界的流,但是有些计算场景需要将数均进行分批的处理,这个分的批就是窗口。 2. 分类 (1)从keyby的角度分: keyed : keyby之后开窗 non-keyed : keyby之前开窗 .windowAll, 并行度只能是1 (2)从类型分: 基于时间的: 滚动、滑动、会话 基于条数的: 滚动、滑动 3. 组成 窗口分配器 Assigner .window(TumblingEventTimeWindow.of()) 触发器 Trigger 驱逐器 Evictor 窗口函数 Function 增量聚合函数(reduce、aggregate)、全窗口函数(process) 4. 窗口的划分 以滚动窗口为例 start = 数据的时间戳 向下 取窗口长度的 整数倍 end = start + 窗口长度 扩展:滑动窗口 start = 数据的时间戳 向下 取滑动步长的 整数倍, 循环往前取(时间 - start <= 长度) end = start + 窗口长度 4)窗口为什么左闭右开 属于窗口的最大时间戳 = end - 1ms 5)窗口什么时候触发输出 时间进展 >= maxTs 6)窗口的生命周期(创建、销毁) 创建:属于本窗口的第一条数据来的时候,现new的,放到一个单例集合 销毁:时间进展 >= maxTs + 窗口允许迟到的时间 ### 4.2 时间分类 - 事件时间:这个指的是数据中所携带的时间 - 处理时间:这个是flink程序处理本条数据的时间 ### 4.3 watermark 1. 概念:watermark是用来衡量事件时间的进展。 2. watermark的特点: ![输入图片说明](/imgs/2024-03-06/MytOAirA1vHUFUYW.png) 3. watermark的生成原理 watermark = 当前最大的时间进展 - 乱序程度 - 1ms 4. watermark的生成分类 - 周期性: 默认每间隔200ms触发一次 - 间歇性: 每来一条数据生成一次 5. watermark的传递 - 一对一 正常传递 - 一对多 广播传递 - 多对多 转化成一对多进行广播传递 当前子任务的上游如果有多个并行子任务的时候,当前子任务会收到多个watermark,它回去取其中最小的。如果有的并行度没有数据,这就会导致并行度不更新,我们可以指定等待时间。 ## 5、状态 ### 5.1 flink中的状态分类 - 托管状态 - 算子状态 - ListState - UnionState - BroadcastState : 这个是在特定场景下使用的。 - 键控状态 - ValueState - ListState - MapState - ReducingState - AggregateState - 这些状态默认是不清理的,所以我们可以设置TTL - 自定义状态 ### 5.2 状态后端 1、状态后端的作用:主要负责管理本地状态的存储和位置 2、状态后端的分类 HashMapStateBackend 将状态存储到TM的JVM堆内存中,状态的存储是全量的。 EmbeddedRocksDBStateBackend 状态是存储到本地的RocksDB数据库中。状态的存储是增量存储的。 ## 6、容错 ### 6.1 checkpoint checkpoint称为检查点,它是由flink自己来进行管理,主要是用来容错的。 savepoint称为保存点,他和checkpoint的原理是一样的,但是savepoint主要是用于: - 版本管理和归档存储 - 更新Flink版本 - 更新应用程序 - 调整并行度 - 暂停应用程序 flink如何保证端到端的数据一致性: (1)source:可重发 (2)flink内部,checkpoint+精确一次性 (3)sink:幂等性/分布式事务 这里重点介绍两阶段提交的原理: (1)第一阶段的预提交是,当sink算子收到barrier的时候,就开始将数据往外写,但是这个时候写入外部系统的数据是不可读的状态,当checkpoint完成之后,会进行二次的提交,二次提交就是将外部系统中不可读的数据变成可读的状态。 这里有个比较容易异或的点就是,checkpoint成功之后,二次提交失败了,会不会导致数据丢失的问题。两阶段提交解决这个问题的方式是,在sink做checkpoint的时候,会将缓存区中待提交的数据也做备份,这样在第二阶段提交失败之后,程序终止,我们从上一个checkpoint恢复数据就可以了。