Flink的网络堆栈是组成flink-runtime模块的核心组件之一,是每个Flink Job的核心。 它连接所有TaskManagers的各个工作单元(子任务)。 这是流式传输数据流经的地方,因此,它对于Flink作业的性能(吞吐量和观察到的延迟)至关重要。 与通过Akka使用RPC的TaskManagers和JobManagers之间的协调通道相比,TaskManagers之间的网络堆栈依赖于更底层的Netty API。
这篇博文是关于网络堆栈的一系列帖子中的第一篇。 在下面的部分中,我们将首先深入了解流操作符所呈现的抽象,然后详细介绍Flink的物理实现和各种优化。 我们将简要介绍这些优化的结果以及Flink在吞吐量和延迟之间的权衡。 本系列中的未来博客文章将详细介绍监控和指标,调整参数和常见的反模式。
Logical View
Flink的网络堆栈在相互通信时为子任务提供以下逻辑视图,例如在keyBy()要求的网络混洗期间:
它抽象了以下三个概念的不同设置:
Subtask output type (
ResultPartitionType
):pipelined (bounded or unbounded): 一旦产生数据,就可以一个接一个地向下游发送数据,作为有界或无限的记录流。
blocking: 仅在生成完整结果时向下游发送数据。
Scheduling type:
all at once (eager): 同时部署作业的所有子任务(对于流应用程序).
next stage on first output (lazy): 一旦任何生产者生成输出,就立即部署下游任务。
next stage on complete output: 当任何或所有生产者生成完整的输出集时,部署下游任务。
Transport:
high throughput: Flink不是一个一个地发送每个记录,而是将一堆记录缓冲到其网络缓冲区中并完全发送它们。 这降低了每个记录的成本并导致更高的吞吐量。
low latency via buffer timeout: 通过减少发送未完全填充的缓冲区的超时,您可能会牺牲吞吐量来延迟。
我们将在下面的部分中查看吞吐量和低延迟优化,这些部分将查看网络堆栈的物理层。 对于这一部分,让我们详细说明输出和调度类型。 首先,重要的是要知道子任务输出类型和调度类型是紧密交织在一起的,只能使两者的特定组合有效。
流水线结果分区是流式输出,需要实时目标子任务才能发送数据。 可以在生成结果之前或首次输出时安排目标。 批处理作业生成有界结果分区,而流式处理作业产生无限结果。
批处理作业也可能以阻塞方式产生结果,具体取决于所使用的运算符和连接模式。 在这种情况下,必须先生成完整的结果,然后才能安排接收任务。 这允许批处理作业更有效地工作并且资源使用更少。
下表总结了有效组合:
1 目前Flink尚未使用。
2 批量/流式统一完成后,这可能适用于流式作业。
此外,对于具有多个输入的子任务,调度以两种方式启动:毕竟或在任何输入生成器生成记录/其完整数据集之后。要调整批处理作业中的输出类型和调度决策,请查看ExecutionConfig #setExecutionMode() - 特别是ExecutionMode - 以及ExecutionConfig #setDefaultInputDependencyConstraint()。