本章将深入分析 Flink 分布式运行时架构如何实现这些概念。

概览

Flink 中的 API

Flink 为流式/批式处理应用程序的开发提供了不同级别的抽象。
在这里插入图片描述

  • Flink API 最底层的抽象为有状态实时流处理。其抽象实现是 Process Function,并且 Process Function 被 Flink 框架集成到了 DataStream API 中来为我们使用。它允许用户在应用程序中自由地处理来自单流或多流的事件(数据),并提供具有全局一致性和容错保障的状态。此外,用户可以在此层抽象中注册事件时间(event time)和处理时间(processing time)回调方法,从而允许程序可以实现复杂计算。

  • Flink API 第二层抽象是 Core APIs。实际上,许多应用程序不需要使用到上述最底层抽象的 API,而是可以使用 Core APIs 进行编程:其中包含 DataStream API(应用于有界/无界数据流场景)和 DataSet API(应用于有界数据集场景)两部分。Core APIs 提供的流式 API(Fluent API)为数据处理提供了通用的模块组件,例如各种形式的用户自定义转换(transformations)、联接(joins)、聚合(aggregations)、窗口(windows)和状态(state)操作等。此层 API 中处理的数据类型在每种编程语言中都有其对应的类。

    Process Function 这类底层抽象和 DataStream API 的相互集成使得用户可以选择使用更底层的抽象 API 来实现自己的需求。DataSet API 还额外提供了一些原语,比如循环/迭代(loop/iteration)操作。

  • Flink API 第三层抽象是 Table API。Table API 是以表(Table)为中心的声明式编程(DSL)API,例如在流式数据场景下,它可以表示一张正在动态改变的表。Table API 遵循(扩展)关系模型:即表拥有 schema(类似于关系型数据库中的 schema),并且 Table API 也提供了类似于关系模型中的操作,比如 select、project、join、group-by 和 aggregate 等。Table API 程序是以声明的方式定义应执行的逻辑操作,而不是确切地指定程序应该执行的代码。尽管 Table API 使用起来很简洁并且可以由各种类型的用户自定义函数扩展功能,但还是比 Core API 的表达能力差。此外,Table API 程序在执行之前还会使用优化器中的优化规则对用户编写的表达式进行优化。

    表和 DataStream/DataSet 可以进行无缝切换,Flink 允许用户在编写应用程序时将 Table API 与 DataStream/DataSet API 混合使用。

  • Flink API 最顶层抽象是 SQL。这层抽象在语义和程序表达式上都类似于 Table API,但是其程序实现都是 SQL 查询表达式。SQL 抽象与 Table API 抽象之间的关联是非常紧密的,并且 SQL 查询语句可以在 Table API 中定义的表上执行。

有状态流处理

什么是状态?

虽然数据流中的许多操作一次只查看一个单独的事件(例如事件解析器),但有些操作会记住跨多个事件的信息(例如窗口操作符)。这些操作称为有状态的。

有状态操作的一些示例:

  • 当应用程序搜索某些事件模式时,状态将存储迄今为止遇到的事件序列。
  • 在每分钟/小时/天聚合事件时,状态会保存待处理的聚合。
  • 在数据点流上训练机器学习模型时,状态会保存模型参数的当前版本。
  • 当需要管理历史数据时,状态允许有效访问过去发生的事件。

Flink 需要知道状态以便使用 检查点 和保存点使其容错。

有关状态的知识还允许重新缩放 Flink 应用程序,这意味着 Flink 负责在并行实例之间重新分配状态。

可查询状态允许您在运行时从 Flink 外部访问状态。

在使用状态时,阅读Flink 的状态后端可能也很有用。Flink 提供了不同的状态后端来指定状态的存储方式和位置。

Keyed State(键控状态)

键控状态在可以被认为是嵌入式键/值存储的地方维护。状态与有状态运算符读取的流一起严格分区和分布。因此,只能在键控流上访问键/值状态,即在键控/分区数据交换之后,并且仅限于与当前事件键关联的值。对齐流和状态的键确保所有状态更新都是本地操作,保证一致性而没有事务开销。这种对齐还允许 Flink 重新分配状态并透明地调整流分区。

在这里插入图片描述
Keyed State 被进一步组织成所谓的Key Groups。Key Groups 是 Fl​​ink 可以重新分配 Keyed State 的原子单元;关键组的数量与定义的最大并行度完全相同。在执行期间,键控运算符的每个并行实例都与一个或多个键组的键一起工作。

状态持久性

Flink 使用流重放和 检查点的组合来实现容错。检查点标记每个输入流中的特定点以及每个运算符的相应状态。流式数据流可以从检查点恢复,同时通过恢复操作符的状态并从检查点重放记录来保持一致性(恰好一次处理语义) 。

检查点间隔是一种权衡执行期间容错开销和恢复时间(需要重放的记录数)的方法。

容错机制不断绘制分布式流数据流的快照。对于状态较小的流式应用程序,这些快照非常轻量级,可以频繁绘制,而不会对性能产生太大影响。流应用程序的状态存储在可配置的位置,通常在分布式文件系统中。

如果出现程序故障(由于机器、网络或软件故障),Flink 会停止分布式流式数据流。然后系统重新启动操作员并将它们重置为最新的成功检查点。输入流被重置到状态快照点。作为重新启动的并行数据流的一部分处理的任何记录都保证不会影响先前的检查点状态。

默认情况下,检查点是禁用的。有关如何启用和配置检查点的详细信息, 请参阅检查点。
为了使这种机制实现其完全保证,数据流源(例如消息队列或代理)需要能够将流倒回到定义的最近点。Apache Kafka具有这种能力,而 Flink 与 Kafka 的连接器利用了这一点。有关Flink 连接器提供的保证的更多信息, 请参阅数据源和接收器的容错保证。
因为 Flink 的检查点是通过分布式快照实现的,所以我们可以互换使用快照和检查点这两个词。通常我们也使用术语快照来表示检查点或保存点。

检查点

Flink 容错机制的核心部分是绘制分布式数据流和算子状态的一致快照。这些快照充当一致的检查点,系统可以在发生故障时回退到这些检查点。Flink 绘制这些快照的机制在“ Lightweight Asynchronous Snapshots for Distributed Dataflows ”中有描述。它受到分布式快照的标准 Chandy-Lamport 算法 的启发,专门针对 Flink 的执行模型量身定制。

请记住,与检查点有关的所有事情都可以异步完成。检查点屏障不会以锁定步骤移动,操作可以异步快照它们的状态。

从 Flink 1.11 开始,检查点可以在有或没有对齐的情况下进行。在本节中,我们首先描述对齐的检查点。

障碍

Flink 分布式快照的一个核心元素是流屏障。这些障碍被注入到数据流中,并作为数据流的一部分与记录一起流动。障碍永远不会超过记录,它们严格按照规定流动。屏障将数据流中的记录分成进入当前快照的记录集和进入下一个快照的记录。每个屏障都带有将其记录推送到其前面的快照的 ID。屏障不会中断流的流动,因此非常轻巧。来自不同快照的多个屏障可以同时在流中,这意味着各种快照可能同时发生。

在这里插入图片描述
流屏障被注入到流源的并行数据流中。快照n的屏障注入点(我们称之为 S n)是源流中快照覆盖数据的位置。例如,在 Apache Kafka 中,此位置将是分区中最后一条记录的偏移量。这个位置S n 被报告给检查点协调器(Flink 的 JobManager)。

然后障碍物向下游流动。当中间算子从其所有输入流中接收到快照n的屏障时,它会向其所有传出流发出快照n的屏障。一旦接收器操作员(流式 DAG 的末端)从其所有输入流中接收到屏障n ,它就会向检查点协调器确认快照n 。在所有接收器都确认快照后,它被认为已完成。

一旦快照n完成,该作业将不再向源请求S n之前的记录,因为此时这些记录(及其后代记录)将通过整个数据流拓扑。
在这里插入图片描述

接收多个输入流的算子需要在快照屏障上对齐输入流。上图说明了这一点:

  • 一旦操作员从传入流接收到快照屏障n,它就不能处理来自该流的任何进一步的记录,直到它也从其他输入接收到屏障n 。否则,它将混合属于快照n的记录和属于快照n+1的记录。
  • 一旦最后一个流接收到屏障n,操作员就会发出所有待处理的传出记录,然后自己发出快照n屏障。
  • 它对状态进行快照并继续处理来自所有输入流的记录,在处理来自流的记录之前处理来自输入缓冲区的记录。
  • 最后,操作员将状态异步写入状态后端。

请注意,所有具有多个输入的算子以及经过洗牌后的算子在消费多个上游子任务的输出流时都需要对齐。

快照操作员状态

当操作符包含任何形式的状态时,该状态也必须是快照的一部分。

操作员在从其输入流接收到所有快照屏障的时间点以及在将屏障发射到其输出流之前的时间点对它们的状态进行快照。此时,所有在障碍之前的记录对状态的更新都已经完成,并且没有任何依赖于障碍之后的记录的更新。因为快照的状态可能很大,所以它存储在一个可配置的状态后端。默认情况下,这是 JobManager 的内存,但对于生产用途,应配置分布式可靠存储(例如 HDFS)。存储状态后,操作员确认检查点,将快照屏障发送到输出流中,然后继续。

生成的快照现在包含:

  • 对于每个并行流数据源,启动快照时流中的偏移量/位置
  • 对于每个运算符,指向作为快照的一部分存储的状态的指针
    在这里插入图片描述
恢复

这种机制下的恢复很简单:一旦发生故障,Flink 会选择最近完成的检查点k。然后系统重新部署整个分布式数据流,并为每个操作员提供作为检查点k的一部分快照的状态。源设置为从位置S k开始读取流。例如在 Apache Kafka 中,这意味着告诉消费者从偏移量S k开始获取。

如果状态是增量快照,则操作员从最新的完整快照的状态开始,然后将一系列增量快照更新应用于该状态。

有关详细信息,请参阅重新启动策略。

未对齐的检查点

检查点也可以在未对齐的情况下执行。基本思想是,只要飞行中的数据成为operator状态的一部分,检查点就可以超越所有飞行中的数据。

请注意,这种方法实际上更接近Chandy-Lamport 算法 ,但 Flink 仍然在源中插入屏障以避免检查点协调器过载。
在这里插入图片描述

该图描述了操作员如何处理未对齐的检查点障碍:

操作员对存储在其输入缓冲区中的第一个屏障做出反应。
它通过将屏障添加到输出缓冲区的末尾,立即将屏障转发给下游操作员。
操作员将所有被超越的记录标记为异步存储,并创建自己状态的快照。
因此,操作员只需短暂停止输入处理以标记缓冲区、转发屏障并创建其他状态的快照。

未对齐的检查点可确保障碍物尽快到达接收器。它特别适用于具有至少一个缓慢移动数据路径的应用程序,其中对齐时间可能长达数小时。但是,由于它增加了额外的 I/O 压力,因此当状态后端的 I/O 成为瓶颈时,它也无济于事。 有关其他限制,请参阅ops中更深入的讨论 。

请注意,保存点将始终对齐。

未结盟恢复

操作员首先在未对齐的检查点中开始处理来自上游操作员的任何数据之前恢复飞行中的数据。除此之外,它执行与对齐检查点恢复期间相同的步骤。

状态后端

存储键/值索引的确切数据结构取决于所选的状态后端。一个状态后端将数据存储在内存中的哈希映射中,另一个状态后端使用RocksDB作为键/值存储。除了定义保存状态的数据结构外,状态后端还实现了获取键/值状态的时间点快照并将该快照存储为检查点的一部分的逻辑。可以在不更改应用程序逻辑的情况下配置状态后端。

在这里插入图片描述

保存点

所有使用检查点的程序都可以从保存点恢复执行。Savepoints 允许在不丢失任何状态的情况下更新你的程序和你的 Flink 集群。

保存点是 手动触发的检查点,它拍摄程序的快照并将其写入状态后端。他们为此依靠常规检查点机制。

保存点类似于检查点,不同之处在于它们 由用户触发并且在更新的检查点完成时不会自动过期。为了正确使用保存点,了解检查点和保存点之间的区别很重要, 检查点与保存点 中描述了这些区别。

恰好一次与至少

对齐步骤可能会增加流式传输程序的延迟。通常,这种额外的延迟大约为几毫秒,但我们已经看到一些异常值的延迟显着增加的情况。对于所有记录都需要持续超低延迟(几毫秒)的应用程序,Flink 有一个开关可以在检查点期间跳过流对齐。一旦操作员从每个输入中看到检查点屏障,仍然会绘制检查点快照。

当对齐被跳过时,操作员继续处理所有输入,即使在检查点n的一些检查点障碍到达之后。这样,操作员还可以在为检查点n拍摄状态快照之前处理属于检查点n+1的元素。在还原时,这些记录将作为重复记录出现,因为它们都包含在检查点n的状态快照中,并且将在检查点n之后作为数据的一部分重放。

对齐仅适用于具有多个前任(连接)的运算符以及具有多个发送者的运算符(在流重新分区/洗牌之后)。正因为如此,只有令人尴尬的并行流操作(、、、…… map())的数据流实际上即使在至少一次模式下 也只提供一次保证。flatMap()filter()

批处理程序中的状态和容错

Flink将批处理程序作为流程序的一种特殊情况执行,其中流是有界的(元素数量有限)。DataSet在内部被视为数据流。因此,上述概念以相同的方式适用于批处理程序,也适用于流式程序,但有一些例外:

  • 批处理程序的容错 不使用检查点。通过完全重播流来进行恢复。这是可能的,因为输入是有界的。这将成本更多地推向恢复,但使常规处理更便宜,因为它避免了检查点。

  • DataSet API 中的有状态操作使用简化的内存内/核外数据结构,而不是键/值索引。

  • DataSet API 引入了特殊的同步(基于超步)迭代,这仅在有界流上才有可能。有关详细信息,请查看迭代文档。

及时流处理

简介

及时流处理是有状态流处理的扩展,其中时间在计算中起一定作用。除其他外,当您进行时间序列分析、基于特定时间段(通常称为窗口)进行聚合时,或者在事件发生的时间很重要的情况下进行事件处理时,就会出现这种情况。

在以下部分中,我们将重点介绍在使用及时的 Flink 应用程序时应考虑的一些主题。

时间概念:事件时间和处理时间

当在流式程序中引用时间(例如定义窗口)时,可以引用不同的时间概念:

  • 处理时间:处理时间是指执行相应操作的机器的系统时间。
    当流程序在处理时间上运行时,所有基于时间的操作(如时间窗口)将使用运行相应操作符的机器的系统时钟。每小时处理时间窗口将包括在系统时钟指示整点时间之间到达特定操作员的所有记录。例如,如果应用程序在上午 9:15 开始运行,则第一个每小时处理时间窗口将包括在上午 9:15 和上午 10:00 之间处理的事件,下一个窗口将包括在上午 10:00 和上午 11:00 之间处理的事件,等等在。
    处理时间是最简单的时间概念,不需要流和机器之间的协调。它提供最佳性能和最低延迟。但是,在分布式和异步环境中,处理时间并不能提供确定性,因为它容易受到记录到达系统(例如从消息队列)的速度,以及记录在系统内操作员之间流动的速度的影响,以及中断(计划的或其他的)。

  • 事件时间:事件时间是每个单独事件在其生产设备上发生的时间。这个时间通常在记录进入 Flink 之前嵌入到记录中,并且可以从每条记录中提取该事件​​时间戳。在事件时间中,时间的进展取决于数据,而不是任何挂钟。事件时间程序必须指定如何生成事件时间水印,这是在事件时间发出进度信号的机制。这种水印机制将在下面的后面部分中 描述。
    在一个完美的世界中,事件时间处理将产生完全一致和确定性的结果,无论事件何时到达或它们的顺序如何。但是,除非已知事件按顺序(按时间戳)到达,否则事件时间处理在等待无序事件时会产生一些延迟。由于只能等待有限的时间段,这限制了事件时间应用程序的确定性。
    假设所有数据都已到达,事件时间操作将按预期运行,并产生正确且一致的结果,即使在处理无序或延迟事件时,或者在重新处理历史数据时也是如此。例如,每小时事件时间窗口将包含所有带有属于该小时的事件时间戳的记录,无论它们到达的顺序或处理时间。(有关更多信息,请参阅有关延迟的部分 。)

请注意,有时当事件时间程序实时处理实时数据时,它们会使用一些处理时间操作以保证它们及时进行。

在这里插入图片描述

事件时间和水印

注意:Flink 实现了数据流模型中的许多技术。有关事件时间和水印的良好介绍,请查看以下文章。

支持事件时间的流处理器需要一种测量事件时间进度的方法。例如,构建每小时窗口的窗口操作员需要在事件时间超过一小时结束时得到通知,以便操作员可以关闭正在进行的窗口。

事件时间可以独立于处理时间(由挂钟测量)进行。例如,在一个程序中,操作员的当前事件时间可能稍微落后于处理时间(考虑到接收事件的延迟),而两者以相同的速度进行。另一方面,另一个流程序可能会通过几个星期的事件时间进行处理,只需几秒钟的处理,通过快速转发已经在 Kafka 主题(或另一个消息队列)中缓冲的一些历史数据。

Flink 中衡量事件时间进度的机制是watermarks。水印作为数据流的一部分流动并带有时间戳t。Watermark(t)声明事件时间已达到该流中的时间t ,这意味着流中不应再有时间戳 t’ <= t 的元素(即时间戳早于或等于水印的事件)。

下图显示了带有(逻辑)时间戳的事件流,以及内联流动的水印。在此示例中,事件是有序的(相对于它们的时间戳),这意味着水印只是流中的周期性标记。
在这里插入图片描述
水印对于无序流至关重要,如下图所示,其中事件不按时间戳排序。一般来说,水印是一个声明,即到流中的那个点,直到某个时间戳的所有事件都应该已经到达。一旦水印到达操作员,操作员可以将其内部事件时钟提前到水印的值。

在这里插入图片描述
请注意,事件时间由新创建的流元素(或多个元素)从生成它们的事件或触发创建这些元素的水印继承。

并行流中的水印

水印在源函数处或之后直接生成。源函数的每个并行子任务通常独立生成其水印。这些水印定义了该特定并行源的事件时间。

当水印流经流媒体程序时,它们会在它们到达的操作员处提前事件时间。每当所有的操作员提前其事件时间时,它就会为其后续运营商在下游生成一个新的水印。

一些算子消耗多个输入流;例如,联合,或keyBy(…)或partition(…)函数后面的运算符。这样一个算子的当前事件时间是其输入流事件时间的最小值。随着它的输入流更新它们的事件时间,操作符也是如此。

下图显示了流经并行流的事件和水印示例,以及操作员跟踪事件时间的示例。
在这里插入图片描述

迟到

某些元素可能会违反水印条件,这意味着即使在Watermark(t)发生之后,还会出现更多时间戳t’ <= t 的元素。事实上,在许多现实世界的设置中,某些元素可以任意延迟,因此无法指定某个事件时间戳的所有元素都发生的时间。此外,即使可以限制延迟时间,将水印延迟太多通常也是不可取的,因为它会导致事件时间窗口的评估延迟太多。

出于这个原因,流媒体程序可能会明确地期望一些后期元素。迟到的元素是在系统的事件时间时钟(由水印表示)已经超过迟到元素的时间戳的时间之后到达的元素。有关如何在事件时间窗口中使用迟到元素的更多信息,请参阅允许迟到。

开窗

聚合事件(例如,计数、总和)在流上的工作方式与批处理不同。例如,不可能计算流中的所有元素,因为流通常是无限的(无界)。相反,流上的聚合(计数、总和等)由窗口限定,例如 “过去 5 分钟的计数”或“最后 100 个元素的总和”。

Windows 可以是时间驱动的(例如:每 30 秒)或数据驱动的 (例如:每 100 个元素)。人们通常区分不同类型的窗口,例如翻滚窗口(无重叠)、滑动窗口(有重叠)和会话窗口(由不活动间隙打断)。
在这里插入图片描述

Flink架构

Flink 是一个分布式系统,需要有效分配和管理计算资源才能执行流应用程序。它集成了所有常见的集群资源管理器,例如Hadoop YARN,但也可以设置作为独立集群甚至库运行。

本节概述了 Flink 架构,并且描述了其主要组件如何交互以执行应用程序和从故障中恢复。

Flink 集群剖析

Flink 运行时由两种类型的进程组成:一个 JobManager 和一个或者多个 TaskManager。

在这里插入图片描述
Client 不是运行时和程序执行的一部分,而是用于准备数据流并将其发送给 JobManager。之后,客户端可以断开连接(分离模式),或保持连接来接收进程报告(附加模式)。客户端可以作为触发执行 Java/Scala 程序的一部分运行,也可以在命令行进程./bin/flink run …中运行。

可以通过多种方式启动 JobManager 和 TaskManager:直接在机器上作为standalone 集群启动、在容器中启动、或者通过YARN等资源框架管理并启动。TaskManager 连接到 JobManagers,宣布自己可用,并被分配工作。

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(请参考 高可用(HA))。

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 Application Cluster
    Flink Application Cluster 是一个专用的Flink Cluster,它只执行来自一个Flink Application的Flink Jobs。Flink Cluster的生命周期与 Flink Application 的生命周期绑定。

  • Flink Job Cluster
    Flink Job Cluster 是一个专用的Flink Cluster,它只执行一个Flink Job。Flink Cluster的 生命周期与 Flink Job 的生命周期绑定。

  • Flink Cluster
    一般情况下,Flink 集群是由一个 Flink JobManager 和一个或多个 Flink TaskManager 进程组成的分布式系统。

  • Event
    Event 是对应用程序建模的域的状态更改的声明。它可以同时为流或批处理应用程序的 input 和 output,也可以单独是 input 或者 output 中的一种。Event 是特殊类型的 Record。

  • ExecutionGraph
    见 Physical Graph。

  • Function
    Function 是由用户实现的,并封装了 Flink 程序的应用程序逻辑。大多数 Function 都由相应的 Operator 封装。

  • Instance
    Instance 常用于描述运行时的特定类型(通常是 Operator 或者 Function)的一个具体实例。由于 Apache Flink 主要是用 Java 编写的,所以,这与 Java 中的 Instance 或 Object 的定义相对应。在 Apache Flink 的上下文中,parallel instance 也常用于强调同一 Operator 或者 Function 的多个 instance 以并行的方式运行。

  • Flink Application
    Flink 应用程序是一个 Java 应用程序,它通过方法(或通过其他方式)提交一个或多个Flink 作业。main()提交作业通常是通过调用execute()执行环境来完成的。
    应用程序的作业可以提交到长时间运行的Flink 会话集群、专用的Flink 应用程序集群或Flink 作业集群。

  • Flink Job
    Flink Job 是通过调用 Flink Application 创建和提交的逻辑图( 也通常称为数据流图) 的运行时表示。execute()

  • JobGraph
    见 Logical Graph。

  • Flink JobManager
    Flink JobManager 是 Flink Cluster 的主节点。它包含三个不同的组件:Flink Resource Manager、Flink Dispatcher、运行每个 Flink Job 的 Flink JobMaster。

  • Flink JobMaster
    JobMaster 是在 Flink JobManager 运行中的组件之一。JobManager 负责监督单个作业 Task 的执行。以前,整个 Flink JobManager 都叫做 JobManager。

  • JobResultStore
    JobResultStore 是一个 Flink 组件,它将全局终止(即完成、取消或失败)的作业的结果保存到文件系统,允许结果比已完成的作业更有效。然后 Flink 使用这些结果来确定作业是否应该在高可用集群中进行恢复。

  • Logical Graph
    逻辑图是有向图,其中节点是 算子 ,边定义算子的输入/输出关系,并对应于数据流或数据集。通过从Flink Application提交作业来创建逻辑图。
    逻辑图通常也称为数据流图。

  • Managed State
    Managed State 描述了已在框架中注册的应用程序的托管状态。对于托管状态,Apache Flink 会负责持久化和重伸缩等事宜。

  • Operator
    Logical Graph 的节点。算子执行某种操作,该操作通常由 Function 执行。Source 和 Sink 是数据输入和数据输出的特殊算子。

  • Operator Chain
    算子链由两个或多个连续的 Operator 组成,两者之间没有任何的重新分区。同一算子链内的算子可以彼此直接传递 record,而无需通过序列化或 Flink 的网络栈。

  • Partition
    分区是整个数据流或数据集的独立子集。通过将每个 Record 分配给一个或多个分区,来把数据流或数据集划分为多个分区。在运行期间,Task 会消费数据流或数据集的分区。改变数据流或数据集分区方式的转换通常称为重分区。

  • Physical Graph
    Physical graph 是一个在分布式运行时,把 Logical Graph 转换为可执行的结果。节点是 Task,边表示数据流或数据集的输入/输出关系或 partition。

  • Record
    Record 是数据集或数据流的组成元素。Operator 和 Function接收 record 作为输入,并将 record 作为输出发出。

  • Flink Session Cluster
    长时间运行的 Flink Cluster,它可以接受多个 Flink Job 的执行。此 Flink Cluster 的生命周期不受任何 Flink Job 生命周期的约束限制。以前,Flink Session Cluster 也称为 session mode 的 Flink Cluster,和 Flink Application Cluster 相对应。

  • State Backend
    对于流处理程序,Flink Job 的 State Backend 决定了其 state 是如何存储在每个 TaskManager 上的( TaskManager 的 Java 堆栈或嵌入式 RocksDB),以及它在 checkpoint 时的写入位置( Flink JobManager 的 Java 堆或者 Filesystem)。

  • Sub-Task
    Sub-Task 是负责处理数据流 Partition 的 Task。“Sub-Task"强调的是同一个 Operator 或者 Operator Chain 具有多个并行的 Task 。

  • Task
    Task 是 Physical Graph 的节点。它是基本的工作单元,由 Flink 的 runtime 来执行。Task 正好封装了一个 Operator 或者 Operator Chain 的 parallel instance。

  • Flink TaskManager
    TaskManager 是 Flink Cluster 的工作进程。Task 被调度到 TaskManager 上执行。TaskManager 相互通信,只为在后续的 Task 之间交换数据。

  • Transformation
    Transformation 应用于一个或多个数据流或数据集,并产生一个或多个输出数据流或数据集。Transformation 可能会在每个记录的基础上更改数据流或数据集,但也可以只更改其分区或执行聚合。虽然 Operator 和 Function 是 Flink API 的“物理”部分,但 Transformation 只是一个 API 概念。具体来说,大多数(但不是全部)Transformation 是由某些 Operator 实现的。

Logo

CSDN联合极客时间,共同打造面向开发者的精品内容学习社区,助力成长!

更多推荐