Flink 网络传输优化技术

  • 时间:
  • 浏览:0

下文的内容会主要围绕数据传输部分展开,逐一介绍其中的优化技术。

40万 人关注的大数据成神之路,真的不来了解一下吗?

40万 人关注的大数据成神之路,选着真的不来了解一下吗?

Flink 计算模型分为逻辑层和执行层,逻辑层主要用于描述业务逻辑,而执行层则负责作业具体的分布式执行。

在上文图二左半部分可不能不能想看 Subtask 之间有三根独立的数据传输管道,实在 这是逻辑视图,而在物理层 Flink 如此多会为维护 Subtask 级别的 TCP 连接,Flink 的 TCP 连接是 TaskManager 级别的。对于每个 Subtask 来说,根据 key 的不同它可不能不能输出数据到下游任意的 Subtask,然后 Subtask 在内内外部会维护下游 Subtask 数目的发送队列,相对地,下游 Subtask 也会维护上游 Subtask 数目的接收队列。相同有4个 TaskManager 上不同的 Subtask 的数据传输会通过 Netty 实现复用和分用跑在同三根 TCP 连接上。

在版本迭代中,Network Stack 老会 在不断改进来适应新的形态学 可能性提高性能。其中在 1.5 版本进行了比较多的改进,包括最重要的 Credit-based 流控制和重构 Task Thread 和 IO Thread 的公司协作 模型。

Object Resue Mode 属于高级选项,当使用 Object Reuse 时用户函数不能 符合 Flink 要求的规范 [2],比如不可不能不能将输入的数据对象存到 State 中,再比如不可不能不能在输出对象然后仍对其进行修改。

众所周知,序列化和反序列化是成本很高的操作,尤其是对于实时计算来说,然后 Flink 在处理如此多要的序列化和反序列化方面做了不少优化工作。

用户提交有4个作业然后,Flink 首先在 client 端执行用户 main 函数以生成描述作业逻辑的拓扑(StreaGraph),其中 StreamGraph 的每个节点是用户定义的有4个算子(Operator)。然后 Flink 对 StreamGraph 进行优化,默认将不涉及 shuffle 然后并行度相同的相邻 Operator 串联起来成为 OperatorChain 形成 JobGraph,其中的每个节点称为 Vertice,是 OperatorChain 或独立的 Operator。

Network Stack 主要包括三项内容,Subtask 的输出模式(数据集有无有界、阻塞或非阻塞)、调度类型(立即调度、等待歌曲上一阶段完成和等待歌曲上一阶段有输出)和数据传输的具体实现(buffer 和 buffer timeout)。

可能性 Flink 维护的 RecordWriter 是 Channel 级别的,当三根数据不能 被输出到多个 Channel 时(比如 broadcast),同样的数据会被序列化多次,导致 着性能上的浪费。然后在 1.7 版本,Flink 将 RecordWriter 的写 Buffer 操作分为将数据反序列化为字节数组和将字节数组拷贝到 Channel 里两步,从而使得多个 Channel 可不能不能复用同有4个反序列化结果 [4]。

从总体上讲,Credit-based 数据流控制处理了阻塞 TCP 连接,使得资源可不能不能更加充分地被利用,另外通过动态分配 Buffer 和拓展队列长度,可不能不能更好地适应生产环境中的不断变化的数据分布及其带来的 Channel 具体情况抖动,都有助缓减部分 Subtask 遇到错误可能性处理速度降低造成的木桶效应。然而这名 新的机制也会引入额外的成本,即每传输有4个 Buffer 要额外一轮 Announce Credit 请求来协商资源,不过从官方的测试来看,整体性能是有显著提升的。

当发送数据时,StreamRecordWriter 将记录反序列化为字节数组,并拷贝至 Netty Server 的 Channel 的有4个 Buffer 中,可能性 Buffer 满了它会提醒 Netty Server 将其发送。此后 StreamRecordWriter 会重新从 BufferPool 申请有4个空的 Buffer 来重复上述过程,直至作业停止。为了实现 batch timeout,Flink 设置了有4个 OutputFlusher 系统进程,它会定时 flush 在 Channel 中的 Buffer,也某些某些通知 Netty Server 有新的数据不能 处理。Netty Server 会在额外分配系统进程来读取该 Buffer 到其已写的位置并将相关内容发送,其前会未写满 Buffer 会继续等待歌曲在 Channel 中等待歌曲后续写入。

在作业拓扑优化阶段,Flink 会尽可能性将多个 Operator 合并为 Operator Chain 来减少 Task 数,可能性 Subtask 内的 Operator 运行在同有4个系统进程,不必能 经过网络传输。尽管 Chained Operator 之间如此网络传输,但不同 Operator 直接共享对象实例如此多安全,可能性对象可能性一并被多个算子并发访问造成意想不可不能不能的后果,然后按照函数式编程的理念,Operator 不应该对外界造成副作用,有4个典型的正面例子某些某些 Scala 中的 Pure Function [5],然后默认具体情况下有4个 Chained Operator 的数据对象传递是通深会拷贝来完成的,而深拷贝则是通过一轮序列化和反序列实现。不过出于性能考虑,自 Flink 提供了 Object Resue Mode 来关闭 Chained Operator 间的数据拷贝。

当三根 Channel 发送端的 Announced Credit 与 接收端的 Unannounced Credit 之和不小于 Blacklog Size 时,该 Channel 占据 正常具体情况,然后占据 反压具体情况。

1.Improving throughput and latency with Flink’s network stack

2.Operating on data objects in functions

3.FLIP-21 - Improve object Copying/Reuse Mode for Streaming Runtime

4.FLINK-9913 - Improve output serialization only once in RecordWriter

4.Pure Functions

这名 实现主要有有4个间题报告 : 一是 OutputFlusher 和 StreamRecordWriter 主系统进程在 Buffer 上会有竞争条件,然后不能 同步操作,当 Channel 数量某些某些时这会带来性能上的损耗;二是当亲们 不能 延迟尽可能性小时,会将 timeout 设为 0 (实际上提供了 flushAlways 选项),然后每写三根记录就 flush 一次,如此 会带来很高的成本,最坏的具体情况下会造成 Netty Server 频繁触发系统进程来读取输入,相当于 为每个 Buffer 设置有4个 event loop。有4个简单的优化想法是,既然 Netty Server 如此 都有 event loop,要怎样会会么不必 Netty 系统进程自己去检测有无有新数据呢?然后 Flink 在 1.5 版本重构了这部分的架构,弃用了要求同步的 OutputFlusher 系统进程,改为使用 StreamRecordWriter 和 Netty 系统进程间的非系统进程安全交互办法 来提高速度,其中核心设计是 BufferBuilder 和 BufferConsumer。

作为底层基础架构,Network Stack 设计的好坏很大程度上决定了有4个计算框架的性能上限,其重要性对于 Flink 开发者可能性有意贡献代码的用户而言如此多多说。而对于 Flink 用户而言,熟悉 Network Stack 也可不能不能你可不能不能在开发阶段提前预计可能性部署后及时发现应用的瓶颈,从而在应对生产环境的部署复杂化性时更加游刃有余。

每个 Vertice 在执行层会被视为有4个 Task,而有4个 Task 对应多个 Subtask,Subtask 的数目即是用户设置的并行度。Subtask 根据 Flink 的调度策略和具体的部署环境及配置,会被派发到相同可能性不同的机器可能性系统进程上,其蕴含上下游依赖关系的 Subtask 会有数据传输的不能 ,这是通过基于 Netty 的 Network Stack 来完成的。

40万 人关注的大数据成神之路,不来了解一下吗?

熟悉网络传输的同学应该对高吞吐和低延迟两者的 trade-off 十分熟悉。网络是以 batch 的形式来传输数据的,而每个 batch 都有带来额外的空间开销(header 等元数据)和时间开销(发送延迟、序列化反序列化延等),然后 batch size 越大则传输的开销越小,然后这也会导致 着延时更高,可能性数据不能 在缓存中等待歌曲的时间越久。对于实时类应用来说,亲们 通常希望延迟可不能不能被限定在有4个合理的范围内,然后业界大多数的做法是设置有4个 batch timeout 来强制发送低于 batch size 的数据 batch,这通常不能 额外设置设置有4个系统进程来实现。

假设当前发送队列有 5 个 Blacklog,而接收队列有 2 个空闲 Credit。首先接收端会通知发送端可不能不能发送 2 个 Buffer,这名 过程称为 Announce Credit。然后发送端接收到请求后将 Channel Credit 设为 2,并发送 1 个 Buffer(然后 Channel Credit 减为 1 ),并将剩余 4 个 Backlog 的信息随着数据一并发给接收端,这名 有4个过程分为称为 Send Buffer 和 Announce Blacklog Size。接收端收到 Backlog Size 之都有向 Buffer Pool 申请 Buffer 以将队列拓展至可不能不能容纳 Backlog Size 的数据,但不一定能完整拿到。可能性队列目前有有4个空闲 Buffer,然后只不能 向 Buffer Pool 申请 3 个 Buffer。假设 3 个 Buffer 都成功申请到,它们会成为 Unannounced Credit,并在下一轮请求中被 Announce。

这名 实现的间题报告 在于当某个 Subtask 出先反压时,反压不仅会作用于该 Subtask 的 Channel,都有误伤到这名 TaskManager 上的某些 Subtask,可能性整个 TCP 连接都被阻塞了。比如在图 3 中,可能性 Subtask 4 有4个 Channel 如此空闲 Buffer,使用同一连接的某些 3 个 Channel 也无法通信。为了处理这名 间题报告 ,Flink 自 1.5 版本引入了 Credit-based 数据流控制为 TCP 连接提供更加细粒度的控制。

具体来说,在接受端的 Buffer 被划分为 Exclusive Buffer 和 Floating Buffer 某种,前者是固定分配到每条接受队列上端的,后者是在 Subtask 级别的 Buffer Pool 里供动态分配。发送队列里的数据称为 Blacklog,而接收队列里的 Buffer 称为 Credit。Credit-Based 数据流控制的核心思想则是根据接收端的空闲 Buffer 数(即 Credit)来控制发送速度,这和 TCP 的速度控制十分例如,不过是作用在应用层。

作为工业级的流计算框架,Flink 被设计为可不能不能每天处理 TB 甚至 PB 级别的数据,某些某些要怎样高吞吐低延迟然后可靠地在算子间传输数据是有4个非常重要的课题。此外,Flink 的数据传输还不能 支持框架某种的形态学 ,例如反压和用于测量延迟的 latency marker。在社区不断的迭代中,Flink 逐渐积累了一套值得研究的网络栈(Network Stack),本文将完整介绍 Flink Network Stack 的实现细节以及关键的优化技术。

本文主要基于 Nico Kruber 在去年 9 月 Flink Forward Berlin 上的分享 [1],涉及到的技术主要有 1.5 版本引入的 Credit-based 数据流控制以及在延迟和吞吐方面做的优化。在结束了了英语 然后,亲们 首先来回顾下 Flink 计算模型里的核心概念,这写概念会在后续被频繁地提及。

Flink 某些某些例外。在上图的 TCP 连接发送端是 Netty Server,而接收端是 Netty Client,两者都有有 event loop 不断处理网络 IO。以实时作业为例子,与 Netty 组件直接交互的是 StreamRecordWriter 和 StreamRecordReader (现已被 StreamWriter 和 StreamInputProcessor 代替),前者负责将 Subtask 最终输出的用 StreamRecord 包装的数据序列化为字节数组并交给 Netty Server,后者负责从 Netty Client 读取数据并反序列化为 StreamRecord。

要注意的是,Object Resue Mode 在 Stream API 中的行为和在 Batch API 中的行为如此多完整一致,前者是处理了 Chained Operator 之间的深拷贝,但不同 Subtask 之间(即使在同一 JVM 内)仍然不能 深拷贝,而后者是每一步都有复用然后的对象,是真正的意义上的 Object Reuse。为此了统一 Object Reuse 在有4个 API 的语义,Flink 社区提出了 FLIP-21 [3],但可能性具体方案如此达成共识目前还如此实现的计划。

BufferBuilder 和 BufferConsumer 以生产者消费者的模式公司协作 ,前者是会被 StreamRecordWriter 调用来写入 Buffer,后者会被 Netty Server 系统进程调用,两者通过 volatile int 类型的位置信息来交换信息。通过这名 办法 ,StreamRecordWriter 不必被 OutputFlusher 阻塞,资源利用率更高,网络传输的吞吐量和延迟均可受益。