Flink的网络堆栈是flink-runtime模块的核心组件之一,也是每个Flink工作的核心。它连接到所有TaskManagers的各种子任务(子任务),因此Flink作业的性能(包括吞吐量和延迟)至关重要。与通过基于Akka的RPC与TaskManager和JobManager进行通信的控制通道不同,TaskManagers之间的网络堆栈依赖于较低级别的Netty API。
本文将首先介绍Flink向Stream运算符公开的高级抽象,然后详细介绍Flink网络堆栈的物理实现以及各种优化,优化效果以及Flink在吞吐量和延迟之间的权衡。
逻辑视图
Flink的网络堆栈为彼此通信的子任务提供以下逻辑视图,例如通过keyBy()操作的数据随机播放:
原理分析|了解有关Apache Flink网络协议栈的更多信息
此过程基于以下三个基本概念:
▼子任务输出类型(ResultPartitionType):
流水线(有限或无限制):一旦生成数据,它就可以继续向下游发送有限或无限的流。
阻止:仅在生成完整结果后向下游发送数据。
▼调度策略:
同时安排所有任务(Eager):同时部署作业的所有子任务(用于流式作业)。
部署上游的第一条记录是Lazy:一旦任何生产者生成任何输出,下游任务就会立即部署。
上游在下游生成完整的数据部署:在任何或所有生产者生成完整数据时部署下游任务。
▼数据传输:
高吞吐量:Flink不是逐个发送每个记录,而是将几条记录缓冲到其网络缓冲区中,并立即将它们全部发送出去。这降低了发送每条记录的成本,从而提高了吞吐量。
低延迟:当网络缓冲区未填充一段时间时,它将触发超时传输。通过减少超时时间,您可以通过牺牲某些吞吐量来获得更低的延迟。随着我们深入了解Flink网络堆栈的物理实现,我们将看到吞吐量延迟的优化。对于这一部分,我们来详细说明输出类型和调度策略。首先,您需要知道子任务的输出类型和调度策略是密切相关的,并且只有两者的某些特定组合是有效的。
Pipelined结果是一个流输出,需要运行目标子任务来接收数据。因此,有必要在上游任务生成数据或生成第一个数据之前安排下游目标任务运行。批处理作业生成有界结果数据,而流作业生成无限结果数据。
批处理作业也可以以阻塞方式生成结果,具体取决于所使用的操作员和连接模式。在这种情况下,您必须等待上游任务生成完整结果,然后再安排下游接收任务运行。这可以提高批处理作业的效率并占用更少的资源。
下表总结了任务输出类型和调度策略的有效组合:
原理分析|了解有关Apache Flink网络协议栈的更多信息
注意:
Flink目前尚未使用
批处理/流量计算可在完成后应用于流式作业。
此外,对于具有多个输入的子任务,调度以两种方式启动:调度任务在所有或任何上游任务生成第一个数据或生成完整数据时运行。要调整批处理作业中的输出类型和调度策略,请参阅ExecutionConfig #setExecutionMode()——,尤其是ExecutionMode和ExecutionConfig #setDefaultInputDependencyConstraint()。
2.物理数据传输
为了理解物理数据连接,请回想一下,在Flink中,不同的任务可以通过Slotsharing组共享相同的Slot。 TaskManager还可以提供多个插槽,以允许将同一任务的多个子任务分派到同一个TaskManager。
对于下图所示的示例,我们假设2个TaskManagers同时部署了2个任务,每个TaskManager有两个Slots。 TaskManager 1执行子任务A.1,A.2,B.1和B.2,TaskManager 2执行子任务A.3,A.4,B.3和B.4。 A和B之间是Shuffle连接类型,例如来自A的keyBy()操作,每个TaskManager上有2x4个逻辑连接,其中一些是本地的,另一些是远程的:原理分析|了解有关Apache Flink网络协议栈的更多信息
不同任务(远程)之间的每个网络连接将在Flink的网络堆栈中获得自己的TCP通道。但是,如果将同一任务的不同子任务安排到同一个TaskManager,则它们与同一TaskManager的网络连接将被多路复用并共享相同的TCP通道以减少资源使用。在我们的例子中,这适用于A.1→B.3,A.1→B.4,以及A.2→B.3和A.2→B.4,如下图所示:
原理分析|了解有关Apache Flink网络协议栈的更多信息
每个子任务的输出称为ResultPartition,每个ResultPartition被分成单独的ResultSubpartition - 每个逻辑通道一个。 Flink的网络协议栈此时不处理单个记录。相反,它将一组序列化记录填充到网络缓冲区中进行处理。每个子任务的本地缓冲区中可用的最大缓冲区数是(每个发送方和接收方一个):
#channels *每通道缓冲区+每个缓冲区的浮动缓冲区
通常不需要配置单个TaskManager上的网络层缓冲区总数。有关如何在需要时进行配置的详细信息,请参阅配置网络缓冲区的文档。
▼原因背压(1)
每当子任务的数据发送缓冲区耗尽时,——数据驻留在子分区的缓冲区队列或基于Netty的较低级别网络堆栈中,生产者被阻止,无法继续发送数据,但是被反转。压力。接收器以类似的方式工作:Netty接收的任何数据都需要通过网络缓冲区传递给Flink。如果相应子任务的网络缓冲区中没有足够的网络缓冲区,Flink将停止从该通道读取,直到缓冲区可用。这将对多路复用上的所有发送子任务进行反压,从而也限制其他接收子任务。下图说明了重载的子任务B.4,它导致多路复用的背压,并且即使B.3具有足够的处理能力,也会导致子任务B.3无法接受和处理数据。