Flink笔记分享(汇总)
Flink笔记分享(汇总)
第一部分 基础概念
Flink 组件
Manager
TaskManager
\1. TaskManager(任务管理器):
- 概念:TaskManager是Flink集群中的工作节点,负责执行具体的任务。
- 职责:TaskManager负责接收和执行任务,管理任务的资源,包括CPU、内存和网络等资源。它还负责与JobManager进行通信,接收任务的分配和调度指令,并将任务的执行结果返回给JobManager。
- 调度时机:TaskManager在启动时会向ResourceManager注册自己的资源,并等待JobManager的任务分配。
- 调度流程:
\1. TaskManager向ResourceManager注册自己的资源。
\2. TaskManager等待JobManager的任务分配。
\3. JobManager根据作业的拓扑结构和任务之间的依赖关系,将任务分配给TaskManager。
\4. TaskManager接收到任务后,根据任务的执行逻辑执行计算,并将结果返回给JobManager。
TaskManager 和 slot
● Flink 中每一个 TaskManager 都是一个JVM进程,它可能会在独立的线程上执行一个或多个子任务
● 为了控制一个 TaskManager 能接收多少个 task, TaskManager 通过 task slot 来进行控制(一个 TaskManager 至少有一个 slot),slot的数量控制着最大的并行度。
● 在当前flink中,每个slot的内存是完全隔离开的,相当于彼此之间互不干扰。
● 尽管slot并不单独分配CPU资源,推荐按照当前TaskManager的CPU核心数量设置slots,这样的话,例如说4核的机器,设置4slot,这样1个slot上一个核心,不用等,相当于独享的状态了。
ResourceManager
\2. ResourceManager(资源管理器):
- 概念:ResourceManager是Flink集群中的资源管理组件,负责分配和管理集群中的资源。
- 职责:ResourceManager负责接收来自JobManager的作业提交请求,并根据集群的资源情况进行资源分配。它管理集群中的资源池,包括CPU、内存和网络等资源,并根据作业的需求进行动态调整。ResourceManager还负责监控TaskManager的健康状态,以及处理TaskManager的故障和重启。
- 调度时机:ResourceManager在Flink集群启动时被启动,负责整个集群的资源管理。
- 调度流程:
\1. ResourceManager启动,并初始化资源池。
\2. JobManager提交作业请求给ResourceManager。
\3. ResourceManager根据作业的资源需求和集群的资源情况,进行资源分配。
\4. ResourceManager将分配的任务发送给相应的TaskManager。
\5. ResourceManager监控TaskManager的健康状态,处理故障和重启。
JobManager
\3. JobManager(作业管理器):
- 概念:JobManager是Flink集群中的主节点,负责整个作业的管理和调度。
- 职责:JobManager负责接收作业提交请求,将作业转换为JobGraph,并进行作业的调度和执行。它还负责管理作业的状态、检查点和故障恢复等功能。
- 调度时机:JobManager在Flink集群启动时被启动,负责整个作业的管理和调度。
- 调度流程:
\1. JobManager启动,并等待作业的提交请求。
\2. 用户提交作业请求给JobManager。
\3. JobManager将作业转换为JobGraph,包括作业的拓扑结构和任务之间的依赖关系。
\4. JobManager根据作业的调度策略,将任务分配给TaskManager。
\5. TaskManager接收到任务后,执行计算,并将结果返回给JobManager。
\6. JobManager监控作业的执行状态,处理检查点和故障恢复等操作。
这些组件共同协作,实现了Flink的分布式流处理和批处理功能。
Slot
在Flink中,”slot”(槽)是指TaskManager中的资源单位,用于执行任务。每个TaskManager都有一定数量的槽,用于并发执行作业的任务。
槽的概念和作用如下:
- 概念:槽是TaskManager中的资源单位,用于执行任务。每个槽可以执行一个任务,一个TaskManager可以拥有多个槽。
- 场景:槽用于并发执行作业的任务,提高作业的处理能力和吞吐量。通过多个槽的并行执行,可以同时处理多个任务,加快作业的执行速度。
- 功能:槽负责接收任务的分配请求,并执行任务的计算逻辑。每个槽可以独立执行任务,拥有自己的资源(CPU、内存等),并与其他槽进行数据交换和通信。
槽的数量由TaskManager的配置决定,可以根据作业的需求进行调整。通过合理配置槽的数量,可以充分利用集群的资源,并提高作业的执行效率。槽的数量也会影响作业的并行度和资源分配,需要根据作业的特点和集群的资源情况进行调优。
在作业执行过程中,JobManager会将作业的任务分配给TaskManager的槽进行执行。每个槽会执行一个任务,处理一部分数据。通过槽的并行执行,可以实现作业的分布式计算和数据处理。槽的数量和资源分配会影响作业的并行度和性能,需要根据作业的需求和集群的资源情况进行合理配置。
其他组件
1. JobGraph(作业图):
- 概念:JobGraph是一个有向无环图,表示一个Flink作业的拓扑结构和任务之间的依赖关系。
- 职责:JobGraph描述了作业中的算子和数据流之间的关系,包括输入输出关系、任务之间的依赖关系等。它是作业提交给JobManager的输入,用于作业的调度和执行。
- 调度时机:JobGraph在作业提交时生成,并在作业调度和执行过程中使用。
2. ExecutionGraph(执行图):
- 概念:ExecutionGraph是一个正在执行的Flink作业的有向无环图,包含了作业的执行状态、任务的调度信息和任务之间的依赖关系。
- 职责:ExecutionGraph是JobManager根据JobGraph生成的执行计划,用于管理作业的执行过程。它记录了作业的执行状态、任务的调度信息、任务之间的依赖关系等,并负责监控任务的执行状态,处理故障恢复和任务重启等操作。
- 调度时机:ExecutionGraph在作业提交后由JobManager生成,并在作业执行过程中使用。
3. Task(任务):
- 概念:Task是Flink作业中的一个执行单元,负责执行具体的计算逻辑。
- 职责:Task负责接收输入数据,执行计算逻辑,并产生输出结果。一个作业可以包含多个任务,每个任务负责处理作业的一部分数据。任务之间可以通过网络进行数据交换和通信。
- 调度时机:Task在作业执行过程中根据调度策略由TaskManager执行。
4. TaskExecutor(任务执行器):
- 概念:TaskExecutor是运行在TaskManager上的组件,负责接收和执行任务,并管理任务的资源。
- 职责:TaskExecutor负责接收来自JobManager的任务分配请求,并根据任务的调度信息执行任务。它管理任务的资源,包括CPU、内存和网络等资源,并负责与其他TaskExecutor进行数据交换和通信。
- 调度时机:TaskExecutor在TaskManager启动时被启动,并在整个作业执行过程中持续运行。
5. BlobServer(资源服务器):
- 概念:BlobServer是用于存储和提供作业所需的资源文件,例如JAR包、配置文件等。
- 职责:BlobServer负责接收和存储作业提交时所需的资源文件,并提供给TaskExecutor进行下载和使用。它提供了高效的资源分发机制,减少了作业提交和执行的时间。
- 调度时机:BlobServer在Flink集群启动时被启动,并在整个作业执行过程中持续运行。
6. CheckpointCoordinator(检查点协调器):
- 概念:CheckpointCoordinator负责管理作业的检查点,以实现容错和恢复。
- 职责:CheckpointCoordinator定期触发作业的检查点操作,将作业的状态和数据保存到持久化存储中。在发生故障时,可以使用检查点来恢复作业的状态,保证作业的一致性和可靠性。
- 调度时机:CheckpointCoordinator在作业执行过程中负责生成和管理检查点。
7. StateBackend(状态后端):
- 概念:StateBackend用于管理作业的状态,包括算子状态和键值状态。
- 职责:StateBackend负责将作业的状态存储在内存或外部存储中,并提供状态的读写接口。它可以根据作业的需求选择不同的存储方式,例如内存、文件系统或分布式存储系统。
- 调度时机:StateBackend在作业执行过程中负责管理状态的读写操作。
8. ShuffleManager(洗牌管理器):
- 概念:ShuffleManager负责将数据进行分区和洗牌,以便在任务之间进行数据交换。
- 职责:ShuffleManager根据作业的需求,将输入数据进行分区和洗牌,并将洗牌后的数据分发给相应的任务进行计算。它提供了高效的数据交换机制,减少了数据传输的开销。
- 调度时机:ShuffleManager在任务执行过程中负责数据的分区和洗牌操作
9. TaskManagerRunner(任务管理器运行器):
- 概念:TaskManagerRunner用于启动和管理TaskManager进程。
- 职责:TaskManagerRunner负责启动TaskManager进程,并提供管理和监控TaskManager的功能。它负责与ResourceManager进行通信,接收任务的分配和调度指令,并将任务的执行结果返回给JobManager。
- 调度时机:TaskManagerRunner在Flink集群启动时被启动,并在整个作业执行过程中持续运行。
10. ResourceManagerRunner(资源管理器运行器):
- 概念:ResourceManagerRunner用于启动和管理ResourceManager进程。
- 职责:ResourceManagerRunner负责启动ResourceManager进程,并提供管理和监控ResourceManager的功能。它负责接收来自JobManager的作业提交请求,并根据集群的资源情况进行资源分配和调度。
- 调度时机:ResourceManagerRunner在Flink集群启动时被启动,并在整个作业执行过程中持续运行。
这些组件共同协作,实现了Flink的分布式流处理和批处理功能。在作业执行过程中,JobGraph和ExecutionGraph描述了作业的结构和执行状态,Task和TaskExecutor负责具体的计算和任务执行,BlobServer存储和提供作业所需的资源文件,CheckpointCoordinator管理作业的检查点以实现容错和恢复,StateBackend管理作业的状态,ShuffleManager负责数据的分区和洗牌,TaskManagerRunner和ResourceManagerRunner分别负责启动和管理TaskManager和ResourceManager进程。通过这些组件的协作,Flink能够实现高效的分布式计算和数据处理。
最基础”单位“
在Flink中还有以下关键词:
\1. Job(作业):
- 概念:Job是一个用户定义的数据处理任务,由一个或多个算子组成的有向无环图。它是Flink中最高级别的抽象,表示一个完整的数据处理流程。
- 场景:Job适用于需要对数据进行复杂的处理和转换的场景,例如数据清洗、数据分析、实时计算等。
- 功能:Job定义了数据处理的逻辑和流程,包括输入数据的来源、数据的转换和计算逻辑、输出数据的目的地等。
\2. 算子(Operator):
- 概念:算子是作业中的一个基本计算单元,负责对输入数据进行转换和处理。算子可以是数据源(Source)、数据接收器(Sink)或数据转换操作(Transformation)。
- 场景:算子适用于对数据进行各种类型的操作,例如过滤、映射、聚合、连接等。
- 功能:算子定义了对输入数据的处理逻辑,可以对数据进行转换、过滤、聚合等操作,并将结果发送给下游算子或输出到外部系统。
\3. Source(数据源):
- 概念:Source是作业中的一个算子,负责从外部系统读取输入数据并生成数据流。它可以从文件、消息队列、数据库等数据源中读取数据。
- 场景:Source适用于需要从外部系统读取数据并进行处理的场景,例如实时流处理、批处理等。
- 功能:Source负责读取输入数据,并将数据发送给下游算子进行处理。它可以根据数据源的特性进行数据的分区和并行读取,实现高吞吐量的数据处理。
\4. Sink(数据接收器):
- 概念:Sink是作业中的一个算子,负责将计算结果输出到外部系统或存储介质。它可以将数据写入文件、数据库、消息队列等目的地。
- 场景:Sink适用于需要将计算结果输出到外部系统或存储介质的场景,例如数据持久化、结果展示、数据传输等。
- 功能:Sink接收来自上游算子的计算结果,并将结果写入外部系统或存储介质。它可以根据目的地的特性进行数据的分区和并行写入,实现高吞吐量的数据输出。
\5. 依赖(Dependency):
- 概念:依赖表示作业中算子之间的关系,描述了数据流的传递和计算顺序。一个算子的输入数据依赖于其他算子的输出数据。
- 场景:依赖用于描述算子之间的数据流和计算顺序,确保数据的正确传递和计算的顺序性。
- 功能:依赖定义了算子之间的数据流和计算顺序,确保每个算子在正确的时机接收和处理数据,保证作业的正确性和一致性。
\6. 任务(Task):
- 任务是作业的最小执行单位,是将算子分配给具体的计算资源进行执行的实体。
- 一个作业可以被分割为多个任务,每个任务负责执行作业中的一个或多个算子。
- 任务的并行度决定了一个算子在执行过程中的并发执行数量。
这些关键词在Flink中扮演着重要的角色。Job表示一个完整的数据处理任务,算子是作业中的基本计算单元,负责数据的转换和处理。Source负责从外部系统读取输入数据,Sink负责将计算结果输出到外部系统。依赖描述了算子之间的关系,确保数据的正确传递和计算的顺序性。通过这些关键词的使用,Flink能够实现灵活、高效的数据处理和计算。
关系
1 |
|
任务提交流程
1、单机调度
2、YARN调度
任务调度流程
客户端不是运行时和程序执行的一部分,但它用于准备并发送 dataflow(JobGraph)给 Master(JobManager),然后,客户端断开连接或者维持连接以等待接收计算结果。
当 Flink 集群启动后,首先会启动一个 JobManger 和一个或多个的 TaskManager。由 Client 提交任务给 JobManager,JobManager 再调度任务到各个 TaskManager 去执行,然后 TaskManager 将心跳和统计信息汇报给 JobManager。 TaskManager 之间以流的形式进行数据的传输。上述三者均为独立的 JVM 进程。
Client 为提交 Job 的客户端,可以是运行在任何机器上(与 JobManager 环境 连通即可)。提交 Job 后,Client 可以结束进程(Streaming 的任务),也可以不结束并等待结果返回。
JobManager 主要负责调度 Job 并协调 Task 做 checkpoint,职责上很像 Storm 的 Nimbus。从 Client 处接收到 Job 和 JAR 包等资源后,会生成优化后的 执行计划,并以 Task 的单元调度到各个 TaskManager 去执行。
TaskManager 在启动的时候就设置好了槽位数(Slot),每个 slot 能启动一个 Task,Task 为线程。从JobManager 处接收需要部署的 Task,部署启动后,与自己的上游建立 Netty 连接,接收数据并处理。
流处理、批处理、Table SQL/API
共有概念
在Apache Flink中,流处理、批处理和Table SQL/API之间有一些共有的概念。下面是它们之间共有的概念:
\1. 数据源(Data Source):数据源是指从外部系统(如文件、消息队列、数据库等)读取数据的组件。
\2. 数据接收器(Data Sink):数据接收器是指将处理结果写入外部系统的组件,如文件、数据库等。
\3. 转换(Transformation):转换是指对数据进行转换、过滤、聚合等操作的过程。
\5. 时间语义(Time Semantics):时间语义是指在数据处理中对事件时间(Event Time)或处理时间(Processing Time)的处理方式。
\6. 并行度(Parallelism):并行度是指任务或操作在集群中同时执行的并发度。可以根据数据规模和计算资源进行调整。
\7. 状态(State):状态是用于存储和管理中间结果的机制。它可以用于跟踪窗口的状态、聚合结果等。
\8. 检查点(Checkpoint):检查点是用于实现容错机制的机制,可以将任务的状态保存到持久化存储中,以便在发生故障时进行恢复。
这些共有的概念反映了Flink作为一个统一的流处理和批处理框架的特点。它们为开发人员提供了一致的编程模型和操作方式,使得可以在同一个应用程序中处理实时数据流和有限数据集,并实现高性能的数据处理和分析。
特有概念
以下是流处理、批处理和Table SQL/API模块中特有的概念的详细说明:
流处理特有的概念:
\1. 水位线(Watermark):水位线用于处理事件时间(Event Time)语义,表示事件流中的事件的时间进度。它用于确定窗口的边界和触发窗口计算。
\2. 窗口(Window):窗口是对事件流进行切分和分组的一种方式,用于聚合、计算或其他操作。窗口可以根据时间、数量或其他条件进行定义和触发。
\3. 处理时间(Processing Time):处理时间是指数据处理的时间,即数据到达处理器的时间。在流处理中,可以使用处理时间进行时间相关的操作,如窗口计算等。
批处理特有的概念:
\1. 数据集(DataSet):数据集是批处理中的基本数据集合,代表有限的数据集。
\2. 批处理作业(Batch Job):批处理作业是对数据集进行离线处理的任务,通常以整个数据集作为一个批次进行处理。
\3. 迭代(Iteration):迭代是批处理中用于进行迭代计算的机制,允许多次迭代地处理数据集。
Table SQL/API特有的概念:
\1. 表(Table):表是Table SQL和Table API中的核心概念,代表了数据的结构化视图。它可以是从数据源读取的数据集,也可以是经过转换和计算得到的中间结果。
\2. 查询(Query):查询是对表进行的操作,包括选择、过滤、聚合等操作。在Table SQL中,查询是使用SQL语句进行的;在Table API中,查询是使用API进行的。
\3. 字段(Field):字段是表中的列,代表了数据的属性。可以通过字段名或索引来引用字段。
以上是流处理、批处理和Table SQL/API模块中特有的概念的详细说明。这些特有的概念反映了每个模块的不同特点和目标,以提供适合不同场景和需求的数据处理和查询能力。
1.1 时间
# 1.2.2 活动时间 - time
事件时间/处理时间/摄取时间
Flink 在流处理节目中支持不同的_时间_概念。
处理时间
(process time):处理算子时,使用本地 机器的 系统时钟
- 处理时间:处理时间是指执行相应 算子操作的机器的系统时间。
当流程序在处理时间运行时,所有基于时间的 算子操作(如时间窗口)将使用运行相应算子的机器的系统时钟。每小时处理时间窗口将包括在系统时钟指示整个小时之间到达特定算子的所有记录。例如,如果应用程序在上午9:15开始运行,则第一个每小时处理时间窗口将包括在上午9:15到上午10:00之间处理的事件,下一个窗口将包括在上午10:00到11:00之间处理的事件,因此上。
处理时间是最简单的时间概念,不需要流和机器之间的协调。它提供最佳性能和最低延迟。但是,在分布式和异步环境中,处理时间不提供确定性,因为它容易受到记录到达系统的速度(例如从消息队列)到记录在系统内的算子之间流动的速度的影响。和停电(预定或其他)。
事件时间
(event time): - 配合水位线,管理区间内的事件;可以无序到达
- 事件时间:事件时间是每个事件在其生产设备上发生的时间。此时间通常在进入Flink之前嵌入记录中,并且 可以从每个记录中提取该_事件时间戳_。在事件时间,时间的进展取决于数据,而不是任何挂钟**。事件时间程序必须指定如何生成_事件时间水印(水位线)_**,这是表示事件时间进度的机制。该水印机制在下面的后面部分中描述。
在一个完美的世界中,事件时间处理将产生完全一致和确定的结果,无论事件何时到达,或者它们的排序。但是,除非事件已知按顺序到达(按时间戳),否则事件时间处理会在等待无序事件时产生一些延迟。由于只能等待一段有限的时间,因此限制了确定性事件时间应用程序的可能性。
假设所有数据都已到达,事件时间 算子操作将按预期运行,即使在处理无序或延迟事件或重新处理历史数据时也会产生正确且一致的结果。例如,每小时事件时间窗口将包含带有落入该小时的事件时间戳的所有记录,无论它们到达的顺序如何,或者何时处理它们。(有关更多信息,请参阅有关迟发事件的部分。)
请注意,有时当事件时间程序实时处理实时数据时,它们将使用一些处理时间 算子操作,以确保它们及时进行。
摄取时间
:Data Source生成时的时间
- 摄取时间(ingestion time):摄取时间是事件进入Flink的时间。在源算子处,每个记录将源的当前时间作为时间戳,并且基于时间的 算子操作(如时间窗口)引用该时间戳。
_摄取时间_在概念上位于_事件时间_和_处理时间之间_。与_处理时间_相比 ,它稍贵一些,但可以提供更可预测的结果。因为 _摄取时间_使用稳定的时间戳(在源处分配一次),所以对记录的不同窗口 算子操作将引用相同的时间戳,而在_处理时间中,_每个窗口算子可以将记录分配给不同的窗口(基于本地系统时钟和任何运输延误)。
与_事件时间_相比,_摄取时间_程序无法处理任何无序事件或后期数据,但程序不必指定如何生成_水印_。
在内部,_摄取时间_与_事件时间_非常相似,但具有自动时间戳分配和自动水印生成函数。
生成
时间戳分配器/水印生成器
时间戳分配器获取流并生成带有带时间戳数据元和水印的新流。如果原始流已经有时间戳和/或水印,则时间戳分配器会覆盖它们。
时间戳分配器通常在数据源之后立即指定,但并非严格要求这样做。例如,常见的模式是在时间戳分配器之前解析(_MapFunction_)和过滤(_FilterFunction_)。在任何情况下,需要在事件时间的第一个 算子操作之前指定时间戳分配器(例如第一个窗口 算子操作)。作为一种特殊情况,当使用Kafka作为流式传输作业的源时,Flink允许在源(或消费者)本身内指定时间戳分配器/水印发射器。有关如何 算子操作的更多信息,请参阅 Kafka Connector文档。
注意:本节的其余部分介绍了程序员必须实现的主要接口,以便创建自己的时间戳提取器/水印发射器。要查看Flink附带的预先实现的提取器,请参阅 预定义的时间戳提取器/水印发射器页面。http://flink.apachecn.org/#/docs/1.7-SNAPSHOT/17?id=tab_scala_2)
1 |
|
具有递增时间戳的分发者
_定期_水印生成的最简单的特殊情况是给定源任务看到的时间戳按升序发生的情况。在这种情况下,当前时间戳始终可以充当水印,因为没有更早的时间戳会到达。
请注意,_每个并行数据源任务_只需要提升时间戳。例如,如果在特定设置中,一个并行数据源实例读取一个Kafka分区,则只需要在每个Kafka分区中时间戳递增。当并行流被混洗,联合,连接或合并时,Flink的水印合并机制将生成正确的水印。http://flink.apachecn.org/#/docs/1.7-SNAPSHOT/18?id=tab_scala_0)
1 |
|
### 允许固定数量的迟到的分配者
定期水印生成的另一个例子是当水印滞后于在流中看到的最大(事件 - 时间)时间戳一段固定的时间。这种情况涵盖了预先知道流中可能遇到的最大延迟的情况,例如,当创建包含时间戳在固定时间段内扩展的数据元的自定义源以进行测试时。对于这些情况,Flink提供了BoundedOutOfOrdernessTimestampExtractor
作为参数的参数maxOutOfOrderness
,即在计算给定窗口的最终结果时,在忽略数据元之前允许数据元延迟的最长时间。延迟对应于结果t - t_w
,其中t
是数据元的(事件 - 时间)时间戳,以及t_w
前一个水印的时间戳。如果lateness > 0
然后,该数据元被认为是迟到的,并且在计算其对应窗口的作业结果时默认被忽略。有关 使用延迟数据元的更多信息,请参阅有关允许延迟的文档。
- Java
- Scala
1 |
|
1.2 状态 / 一致性模型- State
概述
1 |
|
状态类型(键控/算子)
1 |
|
检查点
1 |
|
## 启用和配置检查点
默认情况下,禁用检查点。为了使检查点,调用enableCheckpointing(n)
上StreamExecutionEnvironment
,其中 N 是以毫秒为单位的检查点间隔。
检查点的其他参数包括:
- _完全一次与至少一次_:您可以选择将模式传递给enableCheckpointing(n)
方法,以在两个保证级别之间进行选择。对于大多数应用来说,恰好一次是优选的。至少一次可能与某些超低延迟(始终为几毫秒)的应用程序相关。
- _checkpoint timeout(检查点超时)_:如果当前检查点未完成,则中止检查点的时间。
- _检查点之间的最短时间_:为确保流应用程序在检查点之间取得一定进展,可以定义检查点之间需要经过多长时间。如果将此值设置为例如_5000_,则无论检查点持续时间和检查点间隔如何,下一个检查点将在上一个检查点完成后的5秒内启动。请注意,这意味着检查点间隔永远不会小于此参数。
通过定义“检查点之间的时间”而不是检查点间隔来配置应用程序通常更容易,因为“检查点之间的时间”不易受检查点有时需要比平均时间更长的事实的影响(例如,如果目标存储系统暂时很慢)。
请注意,此值还表示并发检查点的数量为_一_。
- _并发检查点数_:默认情况下,当一个检查点仍处于运行状态时,系统不会触发另一个检查点。这可确保拓扑不会在检查点上花费太多时间,也不会在处理流方面取得进展。可以允许多个重叠检查点,这对于具有特定处理延迟的管道(例如,因为函数调用需要一些时间来响应的外部服务)而感兴趣,但是仍然希望执行非常频繁的检查点(100毫秒) )在失败时重新处理很少。
当定义检查点之间的最短时间时,不能使用此选项。
- _外部化检查点_:您可以将_外围检查点_配置为外部持久化。外部化检查点将其元数据写入持久存储,并且在作业失败时_不会_自动清除。这样,如果您的工作失败,您将有一个检查点可以从中-recovery。有关外部化检查点的部署说明中有更多详细信息。
- _关于检查点错误的失败/继续任务_:这确定如果在执行任务的检查点过程中发生错误,任务是否将失败。这是默认行为。或者,当禁用此选项时,任务将简单地拒绝检查点协调器的检查点并继续运行。
1 |
|
保存点
1 |
|
状态后端
1 |
|
一致性模型
结果保障
1 |
|
1.3 事件 - Event
1 |
|
1.4 并行度
一个特定算子的子任务(subtask)的个数被称之为其并行度(parallelism)。
一般情况下,一个流程序的并行度,可以认为就是其所有算子中最大的并行度。一个程序中,不同的算子可能具有不同的并行度。
并行子任务的分配
A4代表,A任务设置了4个并行度。上面的JobGraph只需要4个slot就能执行起来。
所以,算子里面最大的并行度代表着我们当前需要的slot的数量,也就是我们当前同一时间内,正在并行执行的线程数。
概念
1 |
|
三种并行度
1 |
|
使用
1 |
|
第二部分 DataStream API
2.1 基础概念
水位线
1 |
|
1 |
|
窗口
1 |
|
示例
数据源 - 输入
调用:StreamExecutionEnvironment.addSource(sourceFunction)
自定义:addSource() 接口
```
源是您的程序从中读取输入的位置。您可以使用将附加源附加到程序StreamExecutionEnvironment.addSource(sourceFunction)。Flink附带了许多预先实现的源函数,但您可以通过实现SourceFunction 非并行源,或通过实现ParallelSourceFunction接口或扩展 RichParallelSourceFunction并行源来编写自己的自定义源。
```
DataStream****转换 - 操作
算子的转化:算子将一个或多个DataStream转换为新的DataStream。程序可以将多个转换组合成复杂的数据流拓扑。
转化方式:参见链接 (map、)
数据接收 - 输出
调用:数据接收器使用DataStream并将它们转发到文件,套接字,外部系统或打印它们。Flink带有各种内置输出格式,这些格式封装在DataStreams上的 算子操作后面:
- writeAsText()
/ TextOutputFormat
- 按字符串顺序写入数据元。通过调用每个数据元的_toString()_方法获得字符串。
- writeAsCsv(...)
/ CsvOutputFormat
- 将元组写为逗号分隔值文件。行和字段分隔符是可配置的。每个字段的值来自对象的_toString()_方法。
- print()
/ printToErr()
- 在标准输出/标准错误流上打印每个数据元的_toString()_值。可选地,可以提供前缀(msg),其前缀为输出。这有助于区分不同的_打印_调用。如果并行度大于1,则输出也将与生成输出的任务的标识符一起添加。
- writeUsingOutputFormat()
/ FileOutputFormat
- 自定义文件输出的方法和基类。支持自定义对象到字节的转换。
- writeToSocket
- 根据a将数据元写入套接字 SerializationSchema
- addSink
- 调用自定义接收器函数。Flink捆绑了其他系统(如Apache Kafka)的连接器,这些系统实现为接收器函数。
自定义:addSink() 接口
—–其他操作——-
控制延迟
目的:控制吞吐量 和 延迟
默认情况下,数据元不会逐个传输到网络上(这会导致不必要的网络流量),但会被缓冲。可以在Flink配置文件中设置缓冲区的大小(实际在计算机之间传输)。虽然此方法适用于优化吞吐量,但当传入流速度不够快时,可能会导致延迟问题。要控制吞吐量和延迟,您可以env.setBufferTimeout(timeoutMillis)
在运行环境(或单个 算子)上使用以设置缓冲区填充的最长等待时间。在此之后,即使缓冲区未满,也会自动发送缓冲区。此超时的默认值为100毫秒。
用法:
1 |
|
迭代
迭代 - 迭代器
迭代流程序实现步进函数并将其嵌入到`IterativeStream`。由于DataStream程序可能永远不会完成,因此没有最大迭代次数。相反,您需要指定流的哪个部分反馈到迭代,哪个部分使用`split`转换或转发到下游`filter`。在这里,我们展示了使用过滤器的示例。首先,我们定义一个`IterativeStream`.
例如,这里是从一系列整数中连续减去1直到它们达到零的程序:
1 |
|
收集数据源
即:形如。List<Tuple2<String, Integer>> 等特殊集合类型,转为 DataStream
Flink提供了特殊的数据源,这些数据源由Java集合支持,以方便测试。一旦程序经过测试,源和接收器可以很容易地被读取/写入外部系统的源和接收器替换。
集合数据源可以使用如下:
- Java
- Scala
1 |
|
迭代器数据接收器
Flink还提供了一个接收器,用于收集DataStream结果以进行测试和调试。它可以使用如下:
- Java
- Scala
1 |
|
2.2 Stream Connect
内置连接器
内置Connector 是 Flink 内置的连接器,用于将 Flink 与外部系统进行集成。 Flink 提供多种内置 Connector,如Kafka、Kinesis、Cassandra、Elasticsearch、JDBC 等。
这些内置 Connector 都是一些通用的应用程序接口(API)的实现,Flink 用户可以将这些标准的内置 Connector 用于将 Flink 与其他的数据源或数据汇进行无缝集成。利用这些内置 Connector,Flink 用户可以方便地通过API将数据源和数据汇插入到现有的 Flink 应用程序中,而不必编写自己的代码从外部系统中读取或写入数据。
在 Flink 应用程序中,用户可以使用内置 Connector 根据需要特定于源和汇的属性进行配置。这些 Connector 会自动与 Flink 应用程序中的 State 和 Checkpointing 机制集成,以确保应用程序的一致性和准确性。由于内置 Connector 被广泛使用并得到了社区的强烈支持,因此大多数情况下,Flink 用户可以使用这些内置 Connector 解决数据集成的大多数常见问题,并轻松地将 Flink 与外部系统进行无缝集成和扩展。
SQL获取内置连接器信息
如果您想从 SQL 中获取 Flink 内置连接器的信息,可以使用 Flink SQL CLI 工具或通过 Flink WebUI 进行查询。以下是使用 Flink SQL CLI 工具的示例:
\1. 启动 Flink SQL CLI 工具。您可以通过以下命令启动 Flink SQL CLI 工具:
./bin/sql-client.sh embedded -l /path/to/log注意:将上述命令中的/path/to/log替换为您希望日志文件所在的路径。
\2. 一旦连接成功,在 Flink SQL CLI 工具中,您可以使用以下命令获取当前可用的内置 Connector 列表:
SHOW CATALOGS;这将显示所有可用的 Flink 连接器和目录信息。如果使用内置连接器,则应看到以下目录之一:
a. default_catalog:用于默认目录;
b. kafka:用于 Apache Kafka 连接器;
c. elasticsearch:用于 Elasticsearch 连接器;
d. jdbc:用于 JDBC 连接器;
e. cassandra:用于 Cassandra 连接器;
f. kinesis:用于 Amazon Kinesis 连接器;
\3. 如果要获取特定内置 Connector 的信息,请使用以下命令:
SHOW TABLES IN
例如,在 Kafka Connector 中,您可以使用以下命令查看所有可用的主题列表:
SHOW TABLES IN kafka;这些步骤可以让您通过 Flink SQL CLI 工具获取当前可用的 Flink 内置 Connector 的信息,并查询特定内置 Connector 的详细信息。同时,您也可以通过 Flink WebUI 进行查询,从“Catalog Management”页面查看内置连接器的信息。
Flink支持的内置连接器
,Flink 还提供了多种内置 Connector,以下是 Flink 中常用的一些内置连接器:
● Kinesis Connector:用于将 Flink 与 Amazon Kinesis 集成。
● Elasticsearch Connector:用于将 Flink 与 Elasticsearch 集成。
● Cassandra Connector:用于将 Flink 与 Cassandra 集成。
● JDBC Connector:用于将 Flink 与关系型数据库(如 MySQL、PostgreSQL)集成。
● HBase Connector:用于将 Flink 与 HBase 集成。
● AWS S3 Connector:用于将 Flink 与 Amazon S3 集成。
这些内置 Connector 都是标准 API 的实现,可以方便地将 Flink 应用程序与常见的数据源或数据汇集成。有了这些内置 Connector,Flink 用户可以通过 SQL 访问外部系统中的数据,并使用 Flink 提供的强大的数据处理和流处理能力。同时,您也可以通过编写自定义连接器来将 Flink 集成到其他外部系统中,以实现更多的扩展和集成需求。
第三部分 Flink架构
集群剖析
Flink 运行时由两种类型的进程组成:一个 JobManager 和一个或者多个 TaskManager。
JobManager #
JobManager 具有许多与协调 Flink 应用程序的分布式执行有关的职责:它决定何时调度下一个 task(或一组 task)、对完成的 task 或执行失败做出反应、协调 checkpoint、并且协调从失败中恢复等等。这个进程由三个不同的组件组成:
● ResourceManager
ResourceManager 负责 Flink 集群中的资源提供、回收、分配 - 它管理 task slots,这是 Flink 集群中资源调度的单位(请参考TaskManagers)。Flink 为不同的环境和资源提供者(例如 YARN、Kubernetes 和 standalone 部署)实现了对应的 ResourceManager。在 standalone 设置中,ResourceManager 只能分配可用 TaskManager 的 slots,而不能自行启动新的 TaskManager。
● Dispatcher
Dispatcher 提供了一个 REST 接口,用来提交 Flink 应用程序执行,并为每个提交的作业启动一个新的 JobMaster。它还运行 Flink WebUI 用来提供作业执行信息。
● JobMaster
JobMaster 负责管理单个JobGraph的执行。Flink 集群中可以同时运行多个作业,每个作业都有自己的 JobMaster。
始终至少有一个 JobManager。高可用(HA)设置中可能有多个 JobManager,其中一个始终是 leader,其他的则是 standby(请参考 概览 | Apache Flink)。
TaskManagers #
TaskManager(也称为 worker)执行作业流的 task,并且缓存和交换数据流。
必须始终至少有一个 TaskManager。在 TaskManager 中资源调度的最小单位是 task slot。TaskManager 中 task slot 的数量表示并发处理 task 的数量。请注意一个 task slot 中可以执行多个算子(请参考Tasks 和算子链)。
Tasks 和算子链 #
对于分布式执行,Flink 将算子的 subtasks 链接成 tasks。每个 task 由一个线程执行。将算子链接成 task 是个有用的优化:它减少线程间切换、缓冲的开销,并且减少延迟的同时增加整体吞吐量。链行为是可以配置的;请参考链文档以获取详细信息。
下图中样例数据流用 5 个 subtask 执行,因此有 5 个并行线程。
Task Slots 和资源 #
每个 worker(TaskManager)都是一个 JVM 进程,可以在单独的线程中执行一个或多个 subtask。为了控制一个 TaskManager 中接受多少个 task,就有了所谓的 task slots(至少一个)。
每个 task slot 代表 TaskManager 中资源的固定子集。例如,具有 3 个 slot 的 TaskManager,会将其托管内存 1/3 用于每个 slot。分配资源意味着 subtask 不会与其他作业的 subtask 竞争托管内存,而是具有一定数量的保留托管内存。注意此处没有 CPU 隔离;当前 slot 仅分离 task 的托管内存。
通过调整 task slot 的数量,用户可以定义 subtask 如何互相隔离。每个 TaskManager 有一个 slot,这意味着每个 task 组都在单独的 JVM 中运行(例如,可以在单独的容器中启动)。具有多个 slot 意味着更多 subtask 共享同一 JVM。同一 JVM 中的 task 共享 TCP 连接(通过多路复用)和心跳信息。它们还可以共享数据集和数据结构,从而减少了每个 task 的开销。
默认情况下,Flink 允许 subtask 共享 slot,即便它们是不同的 task 的 subtask,只要是来自于同一作业即可。结果就是一个 slot 可以持有整个作业管道。允许 slot 共享有两个主要优点:
● Flink 集群所需的 task slot 和作业中使用的最大并行度恰好一样。无需计算程序总共包含多少个 task(具有不同并行度)。
● 容易获得更好的资源利用。如果没有 slot 共享,非密集 subtask(source/map())将阻塞和密集型 subtask(window) 一样多的资源。通过 slot 共享,我们示例中的基本并行度从 2 增加到 6,可以充分利用分配的资源,同时确保繁重的 subtask 在 TaskManager 之间公平分配。
Flink 应用程序执行 #
Flink 应用程序 是从其 main() 方法产生的一个或多个 Flink 作业的任何用户程序。这些作业的执行可以在本地 JVM(LocalEnvironment)中进行,或具有多台机器的集群的远程设置(RemoteEnvironment)中进行。对于每个程序,ExecutionEnvironment 提供了一些方法来控制作业执行(例如设置并行度)并与外界交互(请参考 Flink 程序剖析 )。
Flink 应用程序的作业可以被提交到长期运行的 Flink Session 集群、专用的 Flink Job 集群 或 Flink Application 集群。这些选项之间的差异主要与集群的生命周期和资源隔离保证有关。
Flink Session 集群 #
● 集群生命周期:在 Flink Session 集群中,客户端连接到一个预先存在的、长期运行的集群,该集群可以接受多个作业提交。即使所有作业完成后,集群(和 JobManager)仍将继续运行直到手动停止 session 为止。因此,Flink Session 集群的寿命不受任何 Flink 作业寿命的约束。
● 资源隔离:TaskManager slot 由 ResourceManager 在提交作业时分配,并在作业完成时释放。由于所有作业都共享同一集群,因此在集群资源方面存在一些竞争 — 例如提交工作阶段的网络带宽。此共享设置的局限性在于,如果 TaskManager 崩溃,则在此 TaskManager 上运行 task 的所有作业都将失败;类似的,如果 JobManager 上发生一些致命错误,它将影响集群中正在运行的所有作业。
● 其他注意事项:拥有一个预先存在的集群可以节省大量时间申请资源和启动 TaskManager。有种场景很重要,作业执行时间短并且启动时间长会对端到端的用户体验产生负面的影响 — 就像对简短查询的交互式分析一样,希望作业可以使用现有资源快速执行计算。
以前,Flink Session 集群也被称为 session 模式下的 Flink 集群。
Flink Job 集群 #
● 集群生命周期:在 Flink Job 集群中,可用的集群管理器(例如 YARN)用于为每个提交的作业启动一个集群,并且该集群仅可用于该作业。在这里,客户端首先从集群管理器请求资源启动 JobManager,然后将作业提交给在这个进程中运行的 Dispatcher。然后根据作业的资源请求惰性的分配 TaskManager。一旦作业完成,Flink Job 集群将被拆除。
● 资源隔离:JobManager 中的致命错误仅影响在 Flink Job 集群中运行的一个作业。
● 其他注意事项:由于 ResourceManager 必须应用并等待外部资源管理组件来启动 TaskManager 进程和分配资源,因此 Flink Job 集群更适合长期运行、具有高稳定性要求且对较长的启动时间不敏感的大型作业。
以前,Flink Job 集群也被称为 job (or per-job) 模式下的 Flink 集群。
Kubernetes 不支持 Flink Job 集群。 请参考 Standalone Kubernetes 和 Native Kubernetes。
Flink Application 集群 #
● 集群生命周期:Flink Application 集群是专用的 Flink 集群,仅从 Flink 应用程序执行作业,并且 main()方法在集群上而不是客户端上运行。提交作业是一个单步骤过程:无需先启动 Flink 集群,然后将作业提交到现有的 session 集群;相反,将应用程序逻辑和依赖打包成一个可执行的作业 JAR 中,并且集群入口(ApplicationClusterEntryPoint)负责调用 main()方法来提取 JobGraph。例如,这允许你像在 Kubernetes 上部署任何其他应用程序一样部署 Flink 应用程序。因此,Flink Application 集群的寿命与 Flink 应用程序的寿命有关。
● 资源隔离:在 Flink Application 集群中,ResourceManager 和 Dispatcher 作用于单个的 Flink 应用程序,相比于 Flink Session 集群,它提供了更好的隔离。
Flink Job 集群可以看做是 Flink Application 集群”客户端运行“的替代方案。
Flink 的数据传输
TaskManager(slot槽)之间的数据接收和数据发送
发送端:将数据发送到接收端
接收端:接受数据
接收端和发送端端并行度应该相同
基于信用值的流量控制
作用:提高吞吐量和利用率,减少等待时间(低延迟 、高吞吐)
接收端 – 发送信用值
发送端 – 发送积压量
发送端在信用值范围内,尽可能多的发送
接收端在积压量中选择策略修改信用值的优先级
任务链接
将满足要求的算计(同一个机器-本地通信,相同并行度),即可压缩上下游调用关系(融合为一个任务)
Job、Job Instance、task
在Flink中,主要有如下三个概念:Job、JobInstance和Task,它们所代表的含义分别如下:
* Job:表示应用程序的一次执行,是一个与Flink集群交互的最高级别的概念,代表了一个拓扑图,并包括了所有需要运行的Task以及它们之间的数据流。Job拥有一个唯一标识,可以通过该标识来查询和管理这个Job以及它的执行状态。
* JobInstance:一个Job实例表示一个具体的Job执行实例,它包含了Job的配置、Task的初始化状态等信息。当Job提交到Flink集群后,会创建一个JobInstance并为其分配资源,该JobInstance会运行相应的Task并在完成后报告其状态。
* Task:表示一个作业中的任务,它是Flink中的最小执行单元。每个Task都处理一个数据分区(Partition)并通过网络传输与其它任务交换数据(Flink中的Shuffle)。一个Job由多个Task组成。一个JobInstance中的任务可以根据需要动态的进行上下扩展。
简而言之,Job是一次作业的最高级别的概念,代表了数据流拓扑,而JobInstance则是具体的Job执行实例,它的配置和状态信息都存储在Flink的JobManager中,可以用于管理和监控Job的执行状态。Task是在作业执行时是真正进行计算的最小执行单元,每个Task都是同构的,负责处理数据的一部分并互相协作完成作业的结果。
需要注意的是,JobInstance是在Job被提交后到集群处理之前创建的,当Job执行完成后,JobInstance会被销毁。而Task则是在JobInstance的生命周期内,根据不同的需要进行动态创建和销毁。