# flink-tutorial **Repository Path**: kang-kang-kang/flink-tutorial ## Basic Information - **Project Name**: flink-tutorial - **Description**: flink练习 - **Primary Language**: Unknown - **License**: Not specified - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2021-11-03 - **Last Updated**: 2025-06-11 ## Categories & Tags **Categories**: Uncategorized **Tags**: hadoop ## README # Flink 简介 Apache Flink 是一个框架和分布式处理引擎,用于对无界和有界数据流进行有**状态**计算。 - 有状态的流处理:把流处理需要的额外数据保存成一个“状态”,然后针对这条数据进行处理,并且更新状态。 ![img.png](img/state-demo.png) Flink主要特点: - 高吞吐和低延迟。每秒处理数百万个事件,毫秒级延迟。 - 结果的准确性。Flink提供了事件时间(event-time)和处理时间(processing-time)语义。对于乱序事件流,事件时间语义仍然能提供一致且准确的结果。 - 精确一次(exactly-once)的状态一致性保证。 - 可以连接到最常用的外部系统,如Kafka、Hive、JDBC、HDFS、Redis等。 - 高可用。本身高可用的设置,加上与K8s,YARN和Mesos的紧密集成,再加上从故障中快速恢复和动态扩展任务的能力,Flink能做到以极少的停机时间7×24全天候运行。 Flink vs SparkStreaming - Spark以批处理为根本。 - Spark数据模型:Spark 采用 RDD 模型,Spark Streaming 的 DStream 实际上也就是一组组小批数据 RDD 的集合。 - Spark运行时架构:Spark 是批计算,将 DAG 划分为不同的 stage,一个完成后才可以计算下一个。 - Flink以流处理为根本。 - Flink数据模型:Flink 基本数据模型是数据流,以及事件(Event)序列。 - Flink运行时架构:Flink 是标准的流执行模式,一个事件在一个节点处理完后可以直接发往下一个节点进行处理。 Flink 分层 API ![img_1.png](img/flink-api.png) - 有状态流处理:通过底层API(处理函数),对最原始数据加工处理。底层API与DataStream API相集成,可以处理复杂的计算。 - DataStream API(流处理)和DataSet API(批处理)封装了底层处理函数,提供了通用的模块,比如转换(transformations,包括 map、flatmap等),连接(joins),聚合(aggregations),窗口(windows)操作等。注意:Flink1.12以后,DataStream API已经实现真正的流批一体,所以DataSet API已经过时。 - Table API 是以表为中心的声明式编程,其中表可能会动态变化。Table API遵循关系模型:表有二维数据结构,类似于关系数据库中的表;同时API提供可比较的操作,例如select、project、join、group-by、aggregate等。我们可以在表与 DataStream/DataSet 之间无缝切换,以允许程序将 Table API 与 DataStream 以及 DataSet 混合使用。 - SQL这一层在语法与表达能力上与 Table API 类似,但是是以SQL查询表达式的形式表现程序。SQL抽象与Table API交互密切,同时SQL查询可以直接在Table API定义的表上执行。 # Flink 集群架构 Flink 能够在**不同的集群管理框架**下实现**多种部署模式**。 ## Flink 集群运行模式 ### 本地模式(Local Mode) 在本地模式下,Flink作为一个单机应用程序运行,不需要集群资源。这种模式适用于开发和调试阶段,可以在本地机器上快速验证和测试Flink程序的逻辑。 ### 独立模式(Standalone Mode) 在独立模式下,Flink可以作为一个分布式集群运行。它需要在集群中配置一个或多个Flink JobManager和TaskManager。 JobManager负责接收和调度作业,而TaskManager负责执行作业的任务。 这种模式适用于较小规模的部署,可以通过手动配置和管理Flink集群。 ### YARN模式(YARN Mode) 在YARN模式下,Flink可以作为一个YARN应用程序在Hadoop集群上运行。它使用YARN资源管理器来协调和分配资源,并利用HDFS存储数据。YARN 上部署的过程是:客户端把 Flink 应用提交给 Yarn 的 ResourceManager,Yarn 的 ResourceManager 会向 Yarn 的 NodeManager 申请容器。在这些容器上 ,Flink 会部署JobManager 和 TaskManager 的实例,从而启动集群。Flink 会根据运行在 JobManger 上的作业所需要的 Slot 数量动态分配 TaskManager 资源。 ### Mesos模式(Mesos Mode) 在Mesos模式下,Flink可以作为一个Mesos框架在Mesos集群上运行。它使用Mesos主节点和从节点来管理和分配资源。这种模式适用于在Mesos集群上运行Flink应用程序,实现资源的高效利用和动态调度。 ### Kubernetes模式(Kubernetes Mode) 在Kubernetes模式下,Flink可以作为一个Kubernetes应用程序在Kubernetes集群上运行。它使用Kubernetes来管理和分配资源,并支持容器级别的弹性扩缩容。这种模式适用于在Kubernetes集群上运行Flink应用程序,实现灵活的容器化部署。 ## Flink 集群部署模式 Flink 支持3中部署模式:会话模式(Session Mode)、单作业模式(Per-Job Mode)、应用模式(Application Mode)。 ### 会话模式(Session Mode) 会话模式其实最符合常规思维。我们需要先启动一个集群,保持一个会话,在这个会话中通过客户端提交作业。集群启动时所有资源就都已经确定,所以所有提交的作业会竞争集群中的资源。会话模式比较适合于单个规模小、执行时间短的大量作业。 ### 单作业模式(Per-Job Mode) 会话模式因为资源共享会导致很多问题,所以为了更好地隔离资源,我们可以考虑为每个提交的作业启动一个集群,这就是所谓的单作业(Per-Job)模式。 作业完成后,集群就会关闭,所有资源也会释放。 这些特性使得单作业模式在生产环境运行更加稳定,所以是实际应用的首选模式。 需要注意的是,Flink本身无法直接这样运行,所以单作业模式一般需要借助一些资源管理框架来启动集群,比如YARN、Kubernetes(K8S)。 ### 应用模式(Application Mode) 前面提到的两种模式下,应用代码都是在客户端上执行,然后由客户端提交给JobManager的。但是这种方式客户端需要占用大量网络带宽,去下载依赖和把二进制数据发送给JobManager;加上很多情况下我们提交作业用的是同一个客户端,就会加重客户端所在节点的资源消耗。 解决办法就是,直接把应用提交到JobManger上运行。这个JobManager只为执行这一个应用而存在,执行结束之后JobManager也就关闭了,这就是所谓的应用模式。 ### 在 YARN 中提交作业 **会话模式** ``` bin/yarn-session.sh -nm test ``` 可用参数解读: - -d:分离模式,如果你不想让 Flink YARN 客户端一直前台运行,可以使用这个参数,即使关掉当前对话窗口,YARN session 也可以后台运行。 - -jm(--jobManagerMemory):配置 JobManager 所需内存,默认单位 MB。 - -nm(--name):配置在 YARN UI 界面上显示的任务名。 - -qu(--queue):指定 YARN 队列名。 - -tm(--taskManager):配置每个 TaskManager 所使用内存。 **单作业模式** ```shell bin/flink run -d -t yarn-per-job \ -c cn.edu.flink.tutorial.wc \ flink-java-1.0.jar ``` **应用模式** ```shell bin/flink run-application -t yarn-application \ -c cn.edu.flink.tutorial.wc \ flink-java-1.0.jar ``` # Flink 运行时架构 ![img.png](img/flink-architecture.png) 1. 作业管理器(JobManager) JobManager是一个 Flink 集群中任务管理和调度的核心,是控制应用执行的主进程。也就是说,每个应用都应该被唯一的 JobManager 所控制执行。 JobManger 又包含 3 个不同的组件。 1. 分发器:主要负责提供一个 REST 接口,用来提交应用,并且负责为每一个新提交的作业启动一个新的 JobMaster 组件。 2. JobMaster:是 JobManager 中最核心的组件,负责处理单独的作业(Job)。每个 Job 都有一个自己的 JobMaster。 3. 资源管理器:主要负责资源(task slots)的分配和管理,在 Flink 集群中只有一个。 2. 任务管理器(TaskManager) TaskManager 是 Flink 中的工作进程,数据流的具体计算就是它来做的。Flink 集群中必须 至少有一个 TaskManager;每一个 TaskManager 都包含了一定数量的任务槽(task slots)。Slot 是资源调度的最小单位,slot 的数量限制了 TaskManager 能够并行处理的任务数量。 启动之后,TaskManager 会向资源管理器注册它的 slots;收到资源管理器的指令后, TaskManager 就会将一个或者多个槽位提供给 JobMaster 调用,JobMaster 就可以分配任务来执行。 ## 核心概念 ### 并行子任务和并行度 在 Flink 执行过程中,一个算子任务可以被拆分成了多个并行的**子任务**(subtasks),实现任务的并行计算。算子的子任务的个数被称之为其并行度(parallelism)。 并行度设置优先级:算子 > 执行环境 > 任务提交 > 配置文件。 ### 算子间的数据传输(分区策略) 1. roadcastPartitioner:广播分区会将上游数据输出到下游算子的每个实例,适合于大数据和小数据集做JOIN场景。 2. CustomPartitionerWrapper:自定义分区需要用户根据自己实现Partitioner接口,来定义自己的分区逻辑。 3. ForwarPartitioner:用户将记录输出到下游本地的算子实例。它要求上下游算子并行度一样。 4. GlobaPartitioner:数据会被分发到下游算子的第一个实例中进行处理。 5. KeyGroupStreamPartitioner:Hash分区器,会将数据按照key的Hash值输出到下游的实例中。 6. RebalancePartitioner:数据会被循环发送到下游的每一个实例的Task中进行处理。 7. RescalePartitioner:这种分区器会根据上下游算子的并行度,对应的输出到下游算子的每个实例。比如上游并行度为2,编号为A和B。下游并行度为4,编号为1,2,3,4.那么A则把数据循环发送给1,和2,B则把数据循环发送给3和4。 8. ShufflePartitioner:数据会被随即分发到下游算子的每一个实例中进行处理。 在 Flink 中,并行度相同的一对一(one to one)的算子操作,可以直接链接在一起形成一个大的任务(task)。该技术被称为**算子链**(Operator Chain)。 ### 任务槽 对 TaskManager 拥有计算资源进行划分,每一个固定大小的子集被称为任务槽(task slots)。slot 目前仅仅用来隔离内存,不会涉及 CPU 的隔离。 在同一个作业中,不同算子的并行子任务可以放到同一个slot上执行。因此 整个流处理程序的并行度 = 最大的算子并行度 = 运行程序需要的 slot 数量。 注意:任何一个算子的并行度不能设置的超过集群总slot的数量,否则集群不能正常的运行。 ### 作业图转换 逻辑流图(StreamGraph)→ 作业图(JobGraph)→ 执行图(ExecutionGraph)→ 物理图(Physical Graph)。