什么是Flink网格线

Flink网络栈是Flink中的核心组件,是flink-runtime模块的一部分。它连接了所有TaskManager中独立的工作单元(subtask)。这是数据交换的核心部分,任务的吞吐量和延迟都与它息息相关,可以说Flink的网络栈决定了Flink框架本身性能的好坏。

不同于TaskManager、JobManager之间通信所使用的Akka RPC框架,Flink网络栈采用了更底层的网络API,使用的是Netty框架。

它抽象了以下三个概念的不同设置。

(1)Subtask output type (ResultPartitionType):工作单元的输出类型。

  • pipelined (bounded or unbounded):上游一产生数据,就一条条地往下游发送,作为有界或无界的数据流。
  • blocking:直到上游的全部结果就绪才向下游发送数据。

(2)Scheduling type

  • all at once (eager):同时部署所有的工作单元(流式应用采用这种模式)。
  • next stage on first output (lazy):当上游的生产者开始有输出结果的时候,才开始部署下游的工作单元,是一种lazy模式。
  • next stage on complete output:在上游的数据全部就绪之后才开始部署下游的工作单元。

(3)Transport​

  • high throughput:不采用一条条地发送数据的模式,Flink缓存一批数据到网络缓存中,攒批发送。这种方式减少了网络开销的单条边际成本,带来了高吞吐量。
  • low latency via buffer timeout:通过调低发送数据的间隔,牺牲一定的吞吐量以获得更低的延迟。

工作单元的输出类型和调度类型是紧密交织在一起的,两者的特定组合才有效。Pipelined result partition是流式的输出,流式输出需要将数据发送到一个正在工作的工作单元,因此目标任务就需要在上游结果下发之前或者在任务启动之初完成部署。批作业产出有限的结果,而流式作业产出无限的结果。

为了理解真实的数据流转,我们假想一个有4个并发的任务,部署在两个分别有2个Slot的TaskManager上。在Flink中,不同的任务可能会共享同一个Slot, 通过Slot 共享组机制,一个TaskManager可以提供多个Slot来运行一个任务的多个工作单元。

TaskManager 1 运行工作单元A.1、A.2、B.1 和 B.2, 而TaskManager 2 运行工作单元A.3、A.4、B.3和B.4。假设A和B之间的shuffle方式是keyBy(), 这样在每一个TaskManager上都有2×4个逻辑连接,有些走本地传输,有些是通过网络传输,如图1所示。

▲图1 工作单元部署

不同任务之间的每个(远程)网络连接都将在Flink网络栈中获得自己的TCP通道,如果同一个任务的不同工作单元被调度到同一个TaskManager上,那么它们将复用TCP连接用于连接远程TM(多路复用)。在我们的例子中,A.1 → B.3、A.1 → B.4 以及A.2 → B.3、A.2 → B.4将会复用一个TCP连接,如图2所示。

▲图2 数据交换

每个工作单元的输出被称作ResultPartition,每个ResultPartition又根据下游输出结果的不同分区被细分为ResultSubPartition,与下游的inputChannel一一对应。在这个阶段,Flink已经不再单独处理每条记录了,而是将一组序列化完的数据打包并复制到NetworkBuffer中,然后经由Netty传输到下游算子。

本文摘编于《Flink技术内幕:架构设计与实现原理》,经出版方授权发布。(书号:9787111696292)转载请保留文章来源。​