Flink网络栈 深入了解(官方翻译)

1. 导言

flink的网络栈是flink运行的核心组件之一,也是每个flink job的核心。他连接着taskMangager之间的独立的工作单元(子任务,subtask)。这是你的数据的流经之地,因此他对flink的吞吐量和数据数据延迟,有着至关重要的作用。
与taskManager和jobManager之间的使用RPCs via Akka协议的通道不同。taskManger之间的网络栈依赖于Netty更加低层的API。
本博客是flink网络栈系列的第一篇。在本篇中,我们将先从更高层去看一下流运算符所暴露的抽象,然后详细介绍他的物理实现和flink所做的各种优化。我们将简要地介绍这些优化,以及flink在吞吐和验证之间的权衡。本系列后面的博客将会更加详细地关注监控与指标维度,参数调优和常见的反模式(反模式?)。

2. 逻辑视图

flink网络栈提供下面的逻辑视图来展示子任务间数据流动。例如因为keyby而发生网络shuffle的情况。
在这里插入图片描述
该图对以下三个概念进行了抽象

  • 子任务输出类型【Subtask output type (ResultPartitionType)】:
    • 流式的【pipelined】(有界流,无界流):数据产生一产生即可发送数据,可能是一条一条的数据,也可以是有界的数据流或无界的数据流。
    • 批数据【blocking】:当产生了完整的结果之后进行发送
  • 调度类型【Scheduling type】:
    • all at once (eager): 同时部署了job的所有子任务的
    • next stage on first output (lazy): 当上游产生数据开始产生输出时部署下游的子任务
    • next stage on complete output: 当上游数据产生了完整的输出结果后部署下游子任务
  • 数据传输方式【Transport】:
    • 高吞吐:不停与一条数据一条数据发送的方式,flink将会缓存一批消息【record】到网络栈buffer中,再一批一批地发送。这减小了单条消息的耗时,从而获取了更高的吞吐
    • 减少缓冲来获取降低延时,使用bufferTimeOut :你可以通过减小缓存在网络buffer中的超时时长,牺牲掉部分吞吐,降低延时。

下面我们一起在物理层看一下在吞吐与时延见的权衡。这部分我们主要关注输出类型和调度类型。首先我们要明白,子任务的出处类型和调度类型是紧密交织在一起的,这使得只有在两者特定的组合下才有效。
流式的数据结果分区们需要一个live的目标子任务。在结果数据到达之前,这个目标子任务需要被调度起来。批数据产生有界的结果分区,流数据则会产生无界的结果分区。
批处理任务也可以产生堵塞的结果,这取决于操作符和所使用的连接模式。这种情况下,完整的结果需要在下游任务调度起来之前就产生好。这使得批任务更高效,资源消耗更低。

下表总结了一些有意义的组合:

输出类型调度类型适用于
流式,无界一开始调度好所有的子任务流式任务
流式,无界上游结果开始产生时,部署好下游的子任务不适用于flink
流式,有界一开始调度好所有的子任务n/a2
流式,有界一开始调度好所有的子任务批处理任务
堵塞的当输出结果完成后开始部署下游算子批处理任务

n/a2: This may become applicable to streaming jobs once the Batch/Streaming unification is done.

另外子任务有不止一个input,调度以两种方式开始:在所有结果完成之后,或者任何一个上游生产者输出了一个消息|有完整的dataset产生。批任务的输出类型和调度类型的使用请参考:
ExecutionConfig#setExecutionMode()
ExecutionMode in particular
ExecutionConfig#setDefaultInputDependencyConstraint()

3. 物理传输

在flink上不同的任务可以共享一个slot,也可以一个任务使用多个slot。
flink上不同的任务可以通过slot共享组来共享一个slot。在同一个TaskManager上TaskManagers会为一个任务的多个子任务提供超过一个slot使用。
如下图,假设并行度为4,两个taskManager,每个taskManager提供两个slot。TaskManager 1 包含 subtasks A.1, A.2, B.1和B.2。
TaskManager 2 executes subtasks A.3, A.4, B.3和 B.4.
AB任务中间使用keyby进行连接,几个task的分布如下图所示

TaskManager1 slot1TaskManager1 slot2TaskManager2 slot3TaskManager2 slot4
A1A2A3A4
B1B2B3B4

在这里插入图片描述
每个TaskManager上有2*4=8个逻辑连接需要处理,一些是本地连接,一些是远程连接。
不同的task的每个远程连接之间有自己的 TCP channel 。部署在相同的taskMananger上的相同任务下的子任务会共享一个 TCP channel 。如下图TaskManager1上的任务A和B有自己独立的TCP channel。 A1和A2共用一个TCP channel。B1和B2共用一个channel。所以这4个逻辑连接 A.1 → B.3, A.1 → B.4,A.2 → B.3, and A.2 → B.4 将会共用一个TCP channel 。
在这里插入图片描述
每个子任务的结果被称为一个结果分区(ResultPartition)。根据逻辑的channel数,一个ResultPartition将会被分为对应数量的结果子分区( ResultSubpartitions )。需要确认,A1有几个结果分区4个(不管远程还是本地的都算)还是2个(只算远程的)

flink不再处理单条数据,而是存入一组序列化的记录到网络缓存区中。每个子任务在其本地缓存池(发送端和接收端皆有一个)中的最大缓冲区数为:
#channels * buffers-per-channel + floating-buffers-per-gate
单个taskManager总的缓冲区数通常不需要配置。如有需要,参见Configuring the Network Buffers

4. 造成背压

任意一个子任务的发送端的缓冲区池一旦用尽,消息将会堵塞在缓冲区的缓冲队列或者较低的Netty-backed网络堆栈中。生产者堵塞无法继续发送数据,从而感受到了背压。而接收端也存在相似的情况:当任意接收端的缓冲区用尽,接收端flink将会停止从通道中读数据,直到有新的缓冲区。这将会导致这个channel上所有发送端产生背压,并且也会影响其他的下游接收端。下图就是一个背压的例子:B4的缓冲区已经满了,channel中B4的数据将无法继续被B4读取,这个channel将会发生堵塞,从而导致这个channel上游出现背压,而B3虽然有充足的缓冲区,但由于channel堵塞导致B3接收无法接收到自己的数据进行处理。
在这里插入图片描述
为了避免这种情况的发生,flink1.5引进了自己的流控制机制。

5. 基于信用的流控制

基于信用的流控制保证下游有足够的缓冲区去处理上游发来的数据。It is based on the availability of network buffers as a natural extension of the mechanisms Flink had before.之前版本是只能共享一个本地缓冲区,现在每个远程的输入channel有自己的独立的缓冲区,而现在的本地缓冲区则被称为浮动缓冲区(loating buffers),当输入channel需要时进行浮动,每个都input_channel都将可用。

接收端将会告诉发送者当前可用的信用(credits),也即缓冲区数量。一个信用即为一个缓冲区。每个结果子分区将会信用数判断是否要发送数据。只有当有可用信用时,上游缓冲区才会发送消息到lower network stack 中,而且每次发送,信用值将会减一。 除了发送缓冲区里的数据,还会发送当前堵塞的消息量,表明当前的结果子分区中有多少消息处于等待中。接受者会根据这个想浮动缓冲区请求适当的缓冲区,从而更快地减小积压。他会尽量向浮动缓冲区请求和积压数相同的缓冲区,最后或许能拿到部分缓冲区,也可能一个缓冲区都无法申请到。接受者会充分使用申请来的缓冲区,并继续监听是否可用的缓冲区出现。
在这里插入图片描述
基于信用的流控制, buffers-per-channel 决定有多少独有缓冲区可以使用,本地缓冲池的 floating-buffers-per-gate 则可以使让发送端获取到和无流量控制时相同的缓冲区。在网络正常的情况下,这两个参数的默认值能够获得最大吞吐,能够保证无流量控制时相同的吞吐量。你可以根据你实际的网络延迟和带宽来调整参数。
Credit-based flow control will use buffers-per-channel to specify how many buffers are exclusive (mandatory) and floating-buffers-per-gate for the local buffer pool (optional3) thus achieving the same buffer limit as without flow control. The default values for these two parameters have been chosen so that the maximum (theoretical) throughput with flow control is at least as good as without flow control, given a healthy network with usual latencies. You may need to adjust these depending on your actual round-trip-time and bandwidth.

如果没有足够的缓冲区,每个缓冲池将会从全局可用的缓冲池里获取到相同的缓冲区数量。

造成背压2
与无流量控制的接收端背压规则不同,信用机制提供了更直接的控制:接收端无法持续消费的情况下,credit信用值将会变成0,并且停止上游发送者向更低的 network stack发送数据。这只会在当前这一个逻辑通道上出现在背压。他不会堵塞从 multiplexed TCP channel中读取数据。不会影响其他接受者接收处理数据。

6. 我们获得了什么

有了流控制,这个混合tcp通道中其中一个channel堵塞了,不会影响其他逻辑channel。这提供了资源利用率,不仅如此,我们还可以通过控制当前的数据处理量(control over how much data is “on the wire”)来改善checkpoint的对齐。

参考

官方
翻译

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值