本文由社区志愿者 陈政羽 整理,内容源自宋辛童 (五藏) 在 8 月 7 日线上 Flink Meetup 分享的《Flink 1.14 新特性预览》。主要内容为:
文稿 原稿 GitHub 地址 https://github.com/czy006/FlinkClub
此文章为 8 月 7 日的分享整理,1.14 版本最新进展采用注释的方式在文末进行说明。
1.14 新版本原本规划有 35 个比较重要的新特性以及优化工作,目前已经有 26 个工作完成;5 个任务不确定是否能准时完成;另外 4 个特性由于时间或者本身设计上的原因,会放到后续版本完成。[1]
1.14 相对于历届版本来说,囊括的优化和新增功能点其实并不算多。其实通过观察发版的节奏可以发现,通常在 1-2 个大版本后都会发布一个变化稍微少一点的版本,主要目的是把一些特性稳定下来。
1.14 版本就是这样一个定位,我们称之为质量改进和维护的版本。这个版本预计 8 月 16 日停止新特性开发,可能在 9 月份能够和大家正式见面,有兴趣可以关注以下链接去跟踪功能发布进度。
流批一体其实从 Flink 1.9 版本开始就受到持续的关注,它作为社区 RoadMap 的重要组成部分,是大数据实时化必然的趋势。但是另一方面,传统离线的计算需求其实并不会被实时任务完全取代,而是会长期存在。
在实时和离线的需求同时存在的状态下,以往的流批独立技术方案存在着一些痛点,比如:
在这样的背景下,Flink 社区认定了实时离线一体化的技术路线是比较重要的技术趋势和方向。
Flink 在过去的几个版本中,在流批一体方面做了很多的工作。可以认为 Flink 在引擎层面,API 层面和算子的执行层面上做到了真正的流与批用同一套机制运行。但是在任务具体的执行模式上会有 2 种不同的模式:
Flink 1.14 的优化点主要是针对在流的执行模式下,如何去处理有限数据集。之前处理无限数据集,和现在处理有限数据集最大的区别在于引入了 "任务可能会结束" 的概念。在这种情况下带来一些新的问题,如下图:
我们在部分 Sink 使用上,例如下图的 Kafka Sink 上,涉及到 Task 需要依靠 Checkpoint 机制,进行二阶段提交,从而保证数据的 Exactly-once 一致性。
具体可以这样说:在 Checkpoint 过程中,每个算子只会进行准备提交的操作。比如数据会提交到外部的临时存储目录下,所有任务都完成这次 Checkpoint 后会收到一个信号,之后才会执行正式的 commit,把所有分布式的临时文件一次性以事务的方式提交到外部系统。
这种算法在当前有限流的情况下,作业结束后并不能保证有 Checkpoint,那么最后一部分数据如何提交?
在 1.14 中,这个问题得到了解决。Task 处理完所有数据之后,必须等待 Checkpoint 完成后才可以正式的退出,这是流批一体方面针对有限流任务结束的一些改进。
目前 Flink 触发 Checkpoint 是依靠 barrier 在算子间进行流通,barrier 随着算子一直往下游进行发送,当算子下游遇到 barrier 的时候就会进行快照操作,然后再把 barrier 往下游继续发送。对于多路的情况我们会把 barrier 进行对齐,把先到 barrier 的这一路数据暂时性的 block,等到两路 barrier 都到了之后再做快照,最后才会去继续往下发送 barrier。
现有的 Checkpoint 机制存在以下问题:
针对这些痛点,Flink 在最近几个版本一直在持续的优化,Unaligned Checkpoint 就是其中一个机制。barrier 算子在到达 input buffer 最前面的时候,就会开始触发 Checkpoint 操作。它会立刻把 barrier 传到算子的 OutPut Buffer 的最前面,相当于它会立刻被下游的算子所读取到。通过这种方式可以使得 barrier 不受到数据阻塞,解决反压时候无法进行 Checkpoint 的问题。
当我们把 barrier 发下去后,需要做一个短暂的暂停,暂停的时候会把算子的 State 和 input output buffer 中的数据进行一个标记,以方便后续随时准备上传。对于多路情况会一直等到另外一路 barrier 到达之前数据,全部进行标注。
通过这种方式整个在做 Checkpoint 的时候,也不需要对 barrier 进行对齐,唯一需要做的停顿就是在整个过程中对所有 buffer 和 state 标注。这种方式可以很好的解决反压时无法做出 Checkpoint ,和 Barrier 对齐阻塞数据影响性能处理的问题。
Generalized Incremental Checkpoint 主要是用于减少 Checkpoint 间隔,如左图 1 所示,在 Incremental Checkpoint 当中,先让算子写入 state 的 changelog。写完后才把变化真正的数据写入到 StateTable 上。state 的 changelog 不断向外部进行持久的存储化。在这个过程中我们其实无需等待整个 StateTable 去做一个持久化操作,我们只需要保证对应的 Checkpoint 这一部分的 changelog 能够持久化完成,就可以开始做下一次 Checkpoint。StateTable 是以一个周期性的方式,独立的去对外做持续化的一个过程。
这两个过程进行拆分后,就有了从之前的需要做全量持久化 (Per Checkpoint) 变成 增量持久化 (Per Checkpoint) + 后台周期性全量持久化,从而达到同样容错的效果。在这个过程中,每一次 Checkpoint 需要做持久化的数据量减少了,从而使得做 Checkpoint 的间隔能够大幅度减少。
其实在 RocksDB 也是能支持 Incremental Checkpoint 。但是有两个问题:
目前 Unaligned Checkpoint 是在 Flink 1.13 就已经发布了,在 1.14 版本主要是针对 bug 的修复和补充,针对 Generalized Incremental Checkpoint,目前社区还在做最后的冲刺,比较有希望在 1.14 中和大家见面。[2]
这两个构建过程在之前的版本都有 O (n^2) 的时间复杂度,主要问题需要对于每个下游节点去遍历每一个上游节点的情况。例如去遍历每一个上游是不是一个 Pipeline 边连接的关系,或者去遍历它的每一个上游生成对应的 Result Partition 信息。
目前通过引入 group 概念,假设已知上下游 2 个任务的连接方式是 all-to-all,那相当于把所有 Pipeline Region 信息或者 Result Partition 信息以 Group 的形式进行组合,这样只需知道下游对应的是上游的哪一个 group,就可以把一个 O (n^2) 的复杂度优化到了 O (n)。我们用 wordcount 任务做了一下测试,对比优化前后的性能。
从表格中可以看到构建速度具有大幅度提升,构建 Pipeline Region 的性能从秒级提升至毫秒级别。任务部署我们是从第一个任务开始部署到所有任务开始运行的状态,这边只统计了流,因为批需要上游结束后才能结束调度。从整体时间来看,整个任务初始化,调度以及部署的阶段,大概能够减少分钟级的时间消耗。
细粒度资源管理在过去很多的版本都一直在做,在 Flink1.14 终于可以把这一部分 API 开放出来在 DataSteam 提供给用户使用了。用户可以在 DataStream 中自定义 SlotSharingGroup 的划分情况,如下图所示的方式去定义 Slot 的资源划分,实现了支持 DataStream API,自定义 SSG 划分方式以及资源配置 TaskManager 动态资源扣减。
对于每一个 Slot 可以通过比较细粒度的配置,我们在 Runtime 上会自动根据用户资源配置进行动态的资源切割。
这样做的好处是不会像之前那样有固定资源的 Slot,而是做资源的动态扣减,通过这样的方式希望能够达到更加精细的资源管理和资源的使用率。
Window Table-Valued Function 支持更多算子与窗口类型 ,可以看如下表格的对比:
从表格中可以看出对于原有的三个窗口类型进行加强,同时新增 Session 窗口类型,目前支持 Aggregate 的操作。
解决了大家在生成代码超过 Java 最长代码限制,新的代码生成器会对代码进行拆解,彻底解决代码超长的问题。
新版本中,Blink Planner 将成为 Flink Planner 的唯一实现。
在之前的版本中,如果有先后执行的两个 UDF,它的执行过程如下图左方。在 JVM 上面有 Java 的 Operator,先把数据发给 Python 下面的 UDF 去执行,执行后又发回给 Java,然后传送给下游的 Operator,最后再进行一次 Python 的这种跨进程的传输去处理,会导致存在很多次冗余的数据传输。
在 1.14 版本中,改进如右图,可以把它们连接在一起,只需要一个来回的 Java 和 Python 进行数据通信,通过减少传输数据次数就能够达到比较好的性能上的提升。
在以往本地执行实际是在 Python 的进程中去运行客户端程序,提交 Java 进程启动一个迷你集群去执行 Java 部分代码。Java 部分代码也会和生产环境部分的一样,去启动一个新的 Python 进程去执行对应的 Python UDF,从图下可以看出新的进程其实在本地调试中是没有必要存在的。
所以支持 lookback 模式后可以让 Java 的 opt 直接把 UDF 运行在之前 Python client 所运行的相同的进程内,通过这种方式:
本文主要讲解了 Flink1.14 的主要新特性介绍。
欢迎继续关注发版的一些最新动态以及我们在后续的 Release 过程中的一些其他技术分享和专题。
注释
[1] 截至到 8 月 31 日,确定进入新版本的是 33 个,已全部完成。
[2] Generalized Incremental Checkpoint 最终在 1.14 中没有完成。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。