Flink1.13批流合一的介绍

Flink批流合一的介绍

概况

DataStream API支持不同的运行时执行模式,我们可以根据实际的需求和任务的特征来选择这些模式。

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

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

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

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

什么时候可以使用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<String> 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。可以参照下图:

在这里插入图片描述

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函数来处理。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值