Flink1.13批流合一的介绍

官网:Apache Flink Documentation | Apache Flink
概况

以前由于对flink 不是很熟悉,flink 主要是还是流的模式,而且flink 版本更新迭代比较快,对flink 流批一直比较模糊,这几天看看几篇后,终于搞明白了。由于1.12 版本增加流批一体功能,与以前流批模式有所不同,DataStream API支持不同的运行时执行模式,我们可以根据实际的需求和任务的特征来选择这些模式

STREAMING执行模式是DataStream API的“经典”执行行为,应该用于需要持续增量处理并预期无限期在线的无限作业。

此外,还有一种批处理风格的执行模式,我们称之为 BATCH执行模式。 它以一种像批处理框架(如MapReduce)的方式执行作业。 这应用于已知有限的数据源输入并且不会连续运行的有界作业。

Flink对流和批处理的统一方法意味着在有界输入上执行的DataStream应用程序将产生相同的最终结果,而不管配置的执行模式是什么。 注意final在这里的意思是很重要的:以 STREAMING 模式执行的作业可能会产生增量更新(类似数据库中的upserts),而批处理作业在最后只会产生一个最终结果。 如果解析正确,那么最终的结果应该是是相同的,只是实现的方式不同。

通过启用 BATCH 执行,我们可以配置Flink应用额外的优化,只有当我们知道输入的数据源是有限数据的时候才能这样做。 例如,除了允许更高效的任务调度和故障恢复行为的不同shuffle实现外,还可以使用不同的连接/聚合策略。 我们将在下面详细讨论执行行为。

 流批一体API


1 )DataStream API 支持批执行模式
Flink 的核心 API 最初是针对特定的场景设计的,尽管 Table API / SQL 针对流处理和批处理已经实现了统一的 API,但当用户使用较底层的 API 时,仍然需要在批处理(DataSet API)和流处理(DataStream API)这两种不同的 API 之间进行选择。鉴于批处理是流处理的一种特例,将这两种 API 合并成统一的 API,有一些非常明显的好处,比如:

可复用性:作业可以在流和批这两种执行模式之间自由地切换,而无需重写任何代码。因此,用户可以复用同一个作业,来处理实时数据和历史数据。
维护简单:统一的 API 意味着流和批可以共用同一组 connector,维护同一套代码,并能够轻松地实现流批混合执行,例如 backfilling 之类的场景。
考虑到这些优点,社区已朝着流批统一的 DataStream API 迈出了第一步:支持高效的批处理(FLIP-134)。从长远来看,这意味着 DataSet API 将被弃用(FLIP-131),其功能将被包含在 DataStream API 和 Table API / SQL 中。

2) API
Flink提供了多个层次的API供开发者使用,越往上抽象程度越高,使用起来越方便;越往下越底层,使用起来难度越大

Flink1.13批流合一的介绍_第1张图片

Flink1.13批流合一的介绍_第2张图片

注意:在Flink1.12时支持流批一体,DataSetAPI已经不推荐使用了,优先使用DataStream流式API,既支持无界数据处理/流处理,也支持有界数据处理/批处理! 

Overview | Apache Flink
DataSet API # DataSet programs in Flink are regular programs that implement transformations on data sets (e.g., filtering, mapping, joining, grouping). The data sets are initially created from certain sources (e.g., by reading files, or from local collections). Results are returned via sinks, which may for example write the data to (distributed) files, or to standard output (for example the command line terminal). Flink programs run in a variety of contexts, standalone, or embedded in other programs.
https://nightlies.apache.org/flink/flink-docs-release-1.14/docs/dev/dataset/overview/

 
官宣 | Apache Flink 1.12.0 正式发布,流批一体真正统一运行!-阿里云开发者社区
Apache Flink 社区很荣幸地宣布 Flink 1.12.0 版本正式发布!近 300 位贡献者参与了 Flink 1.12.0 的开发,提交了超过 1000 多个修复或优化。
https://developer.aliyun.com/article/780123?spm=a2c6h.12873581.0.0.1e3e46ccbYFFrC

什么时候可以使用BATCH执行模式?


BATCH执行模式只能用于有界数据的Flink Job或者Programs。 有界性是数据源的一个属性,它能说明数据源的所有输入在执行之前是否已知的,或者是否会无限期地出现新数据。 反过来,如果一个Job的所有数据源都是有界的,那么它就是有界的,否则就是无界的。

另一方面, STREAMING 执行模式既可以用于有界数据源的Job,也可以用于无界数据源的Job。

一般来讲,当程序的数据输入有边界时,应该使用 BATCH执行模式,因为这样效率更高。 当您的程序的数据输入是无界的时,您必须使用 STREAMING 执行模式,因为只有这种模式足够通用,能够处理连续的数据流。

一个明显的异常情况是,当您想使用有界Job来引导一些作业状态时,然后想在无界作业中使用这些作业状态。 例如,通过使用 STREAMING模式运行一个有界作业,获取一个savepoint,然后在这个savepoint上恢复一个无界作业。 这是一个非常特殊的案例,当我们允许生成一个Savepoint作为 BATCH执行作业的额外输出时,这个用例可能很快就会过时。

使用STREAMING模式运行有界作业的另一种情况是: 为了测试无界数据输入的Job而使用了有界的数据源。 对于测试来说,在这些情况下使用有界源会更自然一些。

配置BATCH执行模式


通过设置execution.runtime-mode的值可以指定执行模式,有三种可能的情况:

  1. STREAMING 经典的流处理模式(默认)
  2. BATCH DataStream API上的批处理模式
  3. AUTOMATIC 系统自动决定

通过命令行执行Flink应用程序的时候,通过配置flink run的参数来指定;另一种方式是编程方式通过创建或者是配置执行上下文的方式。

下面我们先来看看通过flink run命令行来指定:

bin/flink run -Dexecution.runtime-mode=BATCH examples/streaming/WordCount.jar

下面是在code里面指定:

final StreamExecutionEnvironment env= StreamExecutionEnvironment.getExecutionEnvironment();
env.setRuntimeMode(RuntimeExecutionMode.BATCH);



注意:官方推荐在命令行使用,不推荐在代码中使用。在命令行使用能让Flink程序提供更大的灵活性,而非局限在某一个执行模式

执行行为


下面将概述BATCH和STREAMING模式进行对比。

Task Scheduling And Network Shuffle

Flink job包含多个在工作流图中连接在一起的操作。系统统一决定怎么安排这些操作在不同的机器或者节点上执行,以及他们之间的数据交互。

多个操作或者算子可以链接在一起,我们称为工作链。Flink将一个或者多个(链)操作看做一个统一的调度单元,flink称为task.通常 subtask这个术语是指在taskmanager上并行运行的task的单个实例。

task的调度和数据的网络shuffles在BATCH和STREAMING模式下是不一样的。 多数情况是因为我们知道程序的数据输入是有限流使用BATCH执行模式,这允许Flink使用更有效的数据结构和算法。

下面这个例子来解释任务调度和网络传输的区别:

StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment();
DataStreamSource source = env.fromElements(...);
source.name("source")
    .map(...).name("map1")
    .map(...).name("map2")
    .rebalance()
    .map(...).name("map3")
    .map(...).name("map4")
    .keyBy((value) -> value)
    .map(...).name("map5")
    .map(...).name("map6")
    .sinkTo(...).name("sink");



Operations之间就意味着一对一的连接模式,比如 map(), flatMap,或者是filter(). 这些operations会直接将数据转发到下一个operation,这种情况就允许将这些operation链接在一起称为一个task, Flink也不会在这些operation之间插入network shuffle的操作。

另一方面,像keyBy() 或者 rebalance() 等这样的操作要求数据在不同的并行任务之间传输,这就会导致一个network shuffle(我理解为task之间数据的交叉传输)。

看上面的代码为例:

  • task1: source, map1,和map2
  • task2: map3, map4
  • task3: map5,map6 和 sink

在task1和task2之间, task2和task3之间会有一个network shuffle。可以参照下图:

Flink1.13批流合一的介绍_第3张图片

STREAMING Execution Mode

在STREAMING的执行模式下,所有任务都需要一直在线运行。Flink利用这种特性通过pipeline及时处理最新的数据,这也是连续性和低延迟的流出特征需要的。另外这也要求taskmanager要有足够的系统资源来运行所有的task。

network shuffle是流水线运行的,也就是说数据会被立即发送到下游的任务,同时会在网络层产生一些缓冲。这个是很有必要的,因为在处理一个持续的流数据时,各任务之间不存在时间点来做数据的物化(具体化)。这种处理和BATCH模式不同,在BATCH模式中,中间结果是可以物化的,下面将会讲到。

BATCH Execution Mode

在BATCH执行模式中,Job的多个task可以被划分为多个阶段,然后按阶段执行。Flink能做到按阶段执行时因为它数据是有界的,同时它能在进入下一阶段之前完全处理这一阶段的数据。上面的例子中,Job有三个阶段,分别对应了三个有shuffle barrier分隔的tasks.

不像上面STREAMING模式中发数据立即发送到下游的task, 分阶段处理要求Flink将task的产生中间结果物化到一些非临时的存储中,着这样上游任务执行完成后,下游任务才能读取到这些数据。这将增加处理延迟,但是带来其他有趣的属性。首先,当中间某一个task执行失败的时候,可以回溯到上游最新的可用结果重新开始计算,而不是重新启动整个Job。另外就是BATCH的Job可以在更少的资源(这里的资源值taskmanager的slot数量)上执行,因为系统可以一个一个的执行task。

TaskManagers将保存中间结果,直到下游没有task再使用。(从技术上讲可以保存到消费这些结果的下游任务产生输出结果)。之后,这些中间结果在存储空间足够的情况下将会被保留,以便在出现谷中的时候可以回溯到早起的结果重新开始计算。

State Backends / State

在STREAMING模式下,Flink使用state backend来控制状态的存储方式和 checkpont的工作方式。

在BATCH模式中,配置的后端状态将被忽略。 相反,keyed操作的输入数据按key分组(使用排序),然后依次处理key下面的所有记录。 这允许同时只保留一个key的状态。 当处理到下一个key的数据时,当前key的状态将被丢弃。

Order of Processing

operations(算子)或者用户自定义的算子处理数据的顺序在BATCH和STREAMING模式下是不同的。

STREAMING模式下,用户自定义的函数不会对输入数据的顺序做任何的假设,数据一到就会被处理。

而在STREAMING模式下,有一些operation,Flink会保证其顺序的。排序可能是特定任务的调度,network shuffle和状态后端的副作用,也可能是系统有意识的选择。

我们来区分三种不同类型的输入:

  • broadcast input: 广播输入,来自广播流
  • regular input: 常规输入, 既不是广播,也不是keyed的输入
  • keyed input: keyed的输入,来执KeyedStream的输入


使用多种输入类型的操作或者算子将使用下面的处理顺序:

  • 首先处理广播输入
  • 然后第二部处理常规输入
  • 最后处理keyed输入

对于消费多个常规或广播输入数据的函数(例如CoProcessFunction), Flink有权以任何顺序处理来自该类型的任何输入的数据。

对于使用多个keyed输入的函数(例如KeyedCoProcessFunction), Flink会处理来自所有键输入的单个键的所有记录,然后再转移到下一个keyed输入。

Event Time / Watermarks


当设计到event time支持的时候,Flink的流处理是建立在一个悲观的假设上的,即时间是无序的。如时间戳是t的事件可能在时间戳t+1之后才进入流处理。正因为如此,系统永远不能确定是否还有事件的时间戳t < T(T是未来的某一个时间点)。为了平摊这种无序对最终结果的影响,使系统更实用,在STREAMING模式下,Flink采用了一个方式叫Watermarks. 一个watermark带有一个时间戳T信号,表示在它后面没有t < T的数据出现。

在BATCH模式中,输入数据集是预先知道的,所以不需要watermark,我们可以按时间戳对元素排序,以便按时间顺序处理它们。 对于熟悉流处理的开发者来说,BATCH中我们可以假设有“完美的水印”。

如上所述,在批处理模式中,我们只需要每个键相关联的输入数据的末尾MAX_WATERMARK,或者non-keyed数据集的最后的时间。 基于该方案,所有注册的计时器将在时间结束时触发,用户定义的WatermarkAssigners或WatermarkGenerators将被忽略。 但是,指定一个WatermarkStrategy仍然很重要,因为它的TimestampAssigner仍将用于给事件分配时间戳。

Processing Time


Processing Time 是机器处理事件的时间,是处理事件的机器上的时钟时间。基于这个定义,我们可以知道基于processing time的计算结果是不可重复的,这是因为处理两次相同记录的processing time一定是不相同的。

尽管如此,processing time在STREAMING处理模式下还是很有用的。原因和流处理管道任务经常实时摄取无限流数据,所以event time和processing time是有关系的。此外,由于上述原因,processing time的1小时通常是非常接近event time的1小时。所以使用processing time可以提供源于预期结果的提示的提前触发。

这两种时间的相关性在BATCH模式式下是不存在的,因为在BATCH模式中,输入的数据集都是静态的,而且是已知的。所以,Flink允许用户使用processing time来注册计时器,但是像event time一样,所有的计时器都将在数据输入结束的时候触发。

从概念上讲,我们可以想象,在作业执行期间,processing time不会提前,而是快进到整个输入被处理时的时间结束。

Failure Recovery


在STREAMING模式下,Flink使用checkpoint检查点来进行故障恢复。

使用checkpoint进行故障恢复的一个特征是,再出现故障的是时候,Flink将从最新的checkpoint重新启动所有正在运行的任务。这可能比我们在BATCH模式下执行的操作代价更高,但是你这也是允许使用BATCH模式执行的原因。

在BATCH执行模式下,Flink会尝试回溯到之前处理阶段,该阶段的中间结果任然是可用的。一般而言,只有失败的任务需要重新启动,这与从checkpoint重启所有任务相比更高效,更节省时间。

重要的考虑


对比经典的STREAMING执行模式,在BATCH模式下,有些东西不像我们的预期那样工作。一些特性在两种模式下是互不支持的。

在BATCH模式下的行为的改变:

类似 reduce() 或者 sum() 这样的滚动操作在STREAMING模式下会做增量的更新,而在BATCH模式下,这些操作(reduce/sum)不会滚动,它们只会计算出最后的结果。

BATCH模式下不支持的行为:

  • checkpointing和任务与checkpointing有关的操作在BATCH模式下都不会起作用。
  • 不支持迭代流,参考迭代器流

实现自定义的操作符时要小心,否则会出现一些不当的行为。值得注意的是,自定义的操作符是Flink提供的高级用法,对大多数开发者来说,最好还是使用keyed process函数来处理。

 

你可能感兴趣的:(flink,flink)