流模式 vs 批模式:你选对了吗?
![流模式vs批模式:你选对了吗?](https://static001.geekbang.org/infoq/e3/e345f3daf348b26c39ff2eed58abe1d3.png)
摘要:本文由阿里云 Flink 团队刘文聪老师在撰写。文章分析了 Flink 的流批模式在不同维度存在的特点与差异,帮助开发者朋友们更好地理解 Flink 的流批模式。内容主要为以下四部分:
吞吐
资源使用
容错代价
结论
在大数据处理领域,Apache Flink 以其独特的流批一体架构,为开发者提供了强大的实时数据处理能力。然而,在选择 Flink 作业的执行模式时,开发者们普遍的经验是:流模式适用于对实时性要求较高的场景,如实时日志监控、在线欺诈检测等。这些场景要求系统能够持续处理不断产生的数据流,并在尽可能短的延迟时间内生成结果。而批模式则更适用于对大量历史数据进行统一处理,对延迟不敏感,但注重整个作业的吞吐的场景,如离线数据分析、报表生成等。
实时性要求较高的场景使用流模式毋庸置疑,但对于非实时处理的场景,是否一定要选择批模式呢?笔者最近参与了一次离线作业的调优工作,这个作业的主要任务是数据同步,并且在批模式下执行,其逻辑相对简单但包含了较多的 Shuffle 步骤。在测试过程中,笔者尝试使用流模式来执行该作业,却意外地发现,使用流模式执行该作业的时间竟然比批模式更短,这也意味着此时流模式具有更高的吞吐。这一发现出乎我的意料:难道流模式在非实时场景下也可能具备更高的吞吐量?
该现象引起了笔者的进一步思考。经过分析发现,在吞吐方面,如果考虑作业处理逻辑与数据量等因素,流模式在特定条件下的确可以超过批模式的表现。此外,流模式在资源使用等方面也具备一定的优势。这意味着,对于一些原先基于批模式执行的作业,其实可以尝试切换到流模式来获得更高的执行效率。
接下来,我们将详细分析 Flink 的流批模式在不同维度存在的特点与差异,帮助开发者朋友们更好地理解 Flink 的流批模式,也能够更加灵活地进行选择。
一、吞吐
批模式在包含大量有状态算子(如 Join、Aggregate、Reduce)的作业中,通常能够表现出更好的吞吐性能。这是因为 Flink 在批模式下,能够充分利用数据有边界的特性,优化处理效率。例如,Join 算子可以选择 Hash / SortMerge / NestedLoop 等全量处理场景下更加高效的算法;数据在进入按 Key 聚合的算子前会预先根据 Key 进行排序,算子可以基于数据的有序性,面向单 Key 直接在内存中保存 State,不需要依赖外部存储。
为了说明这一点,笔者选择了 Nexmark 基准测试来对比相同资源下 Flink 分别在流模式和批模式下的性能结果(由于资源限制原因未选择 TPC-DS),在绝大部分的 Query 上,批模式的执行时长相较于流模式能够降低约 17%~92%,这验证了批模式在吞吐上具有一定的优势,相关结果如下图所示:
![](https://static001.geekbang.org/infoq/9b/9be45cc523ce6c04aaf66e8105dfb880.webp?x-oss-process=image%2Fresize%2Cp_80%2Fformat%2Cpng)
然而,其中 q10 批模式比流模式要更慢,这是由于批模式下对应的 Sink 节点额外引入了排序步骤,该步骤会消耗一定的 CPU 资源。同时,如果作业中仅包含无状态算子(如 Map、Filter),并且包含了较多 Shuffle 步骤,流模式可能会更加高效。以上述实验结果中的 q0 为例,作业中仅包含了 Source->Sink 的 ETL 逻辑,由于 Flink 进行了 OperatorChain 优化,此时作业中没有 Shuffle,执行时长上批模式比流模式执行时间缩短了约 18%。但在实际生产情况下,往往存在很多无状态作业,由于作业中的算子并行度不完全一致或者拓扑结构等原因导致无法全部 Chain 在一起。为了测试这种情况,笔者将 Flink 的 OperatorChain 功能关闭后再次对 q0 进行了对比,此时 q0 的执行过程会包含 Shuffle,作业拓扑如下图所示:
![](https://static001.geekbang.org/infoq/76/76dd4223d07b318f103cb68754339373.webp?x-oss-process=image%2Fresize%2Cp_80%2Fformat%2Cpng)
经过再次进行测试后发现,此时流模式的执行时间比批模式缩短了大约 35%。笔者通过火焰图对性能瓶颈进行定位,发现在作业执行过程中,批模式的 Shuffle 过程消耗了比流模式更多的 CPU 资源,如下图所示:
![](https://static001.geekbang.org/infoq/9c/9ccafff0cfa0c5ea02dc9430e7274238.webp?x-oss-process=image%2Fresize%2Cp_80%2Fformat%2Cpng)
这是因为 q0 是无状态的,并且包含了大量的 Shuffle 步骤。流模式下,Shuffle 数据通过内存传输,不需要写入磁盘。然而,在批模式下,由于处理逻辑较为简单,算子执行上的优化效果不明显,同时 Shuffle 的数据需要落盘,导致开销更大。
非实时处理的场景,包含大量无状态算子且存在 Shuffle 的作业适合使用流模式,这是由于流模式能够发挥其内存 Shuffle 的优势,这种优势在数据量大的情况下会更加明显;包含大量有状态的算子的作业适合使用批模式,这是由于批模式下有状态算子更加高效,此时批模式将更有优势。
二、资源使用
在资源使用方面,流模式下,数据会以流水线模式在算子间实时传递并被处理。因此,流模式下所有的 Task 会同时部署和执行,保证数据能够在最短的时间内被处理。这意味着作业在启动时就需要获取全部 Task 所需要的资源,并且作业会持续占用集群的 CPU、内存和网络资源。
![](https://static001.geekbang.org/infoq/9b/9bc97cd547f770f056a5c7f9da50895b.webp?x-oss-process=image%2Fresize%2Cp_80%2Fformat%2Cpng)
而批模式下作业中的 Task 按照数据依赖关系被划分成不同的 Stage,Stage 内的并行 Task 不需要同时运行, Stage 之间按照顺序依次进行调度并计算。因此作业启动时最低只需要满足一个 Stage 中的单个 Task 所需的资源即可。
![](https://static001.geekbang.org/infoq/f6/f69d501e6a45f091d4e74d80b816f344.webp?x-oss-process=image%2Fresize%2Cp_80%2Fformat%2Cpng)
流模式相较于批模式的优点在于能够保证作业具有持续稳定的数据处理能力。这是由于流模式下,作业只有将所需的全部资源都申请到后才会启动,并且在运行过程中,作业持有的资源总量不会发生改变。而批模式下,由于作业分 Stage 顺序依次进行处理,每个 Stage 的执行时间受可用资源总量的影响,资源充足时可以同时启动其中的所有 Task,资源不足时只能同时启动其中的部分 Task,Stage 的执行时间会变慢。相比之下,流模式可以保证稳定的数据处理能力,不会受当前的资源总量的影响。
批模式相较于流模式的优点在于能够提高集群整体的资源利用率,减少资源浪费。正如前文所述,批模式下作业对资源的使用具有很强的适应性,无论资源是否充足都可以利用现有资源启动作业。这种特性使得不同的批作业同时运行在一个集群中时,可以实现“削峰填谷”的效果。而流模式下,如果剩余的可用资源小于单个作业所需的全部资源,那么该作业将无法启动,剩余的资源也无法被利用。
可以看出,需要持续且稳定的数据处理能力的作业适合使用流模式,这是由于流模式要求作业在启动前就分配到足够的资源,这可以确保作业启动后不受剩余可用资源的影响;对延迟不敏感,并且要求能最大化利用现有资源的作业适合使用批模式,这是由于批模式可以灵活适应资源多寡的波动。
三、容错代价
流模式采用了基于 Checkpoint 的快照恢复机制进行容错。当发生故障时,整个作业的所有 Task 会从最近一次的 Checkpoint 恢复 State ,并且从对应的消费位点开始处理数据,不需要对所有的历史数据进行重新计算。
![](https://static001.geekbang.org/infoq/98/98f2aae479bdb4f367b0c705f9ebf332.webp?x-oss-process=image%2Fresize%2Cp_80%2Fformat%2Cpng)
而批模式的容错主要依赖于 Task 的重跑。当发生故障时,对于发生故障的 Task,它的计算结果都会被丢弃,然后该 Task 将从头开始执行。
流模式和批模式的容错代价需要从多方面进行衡量。
对于流模式,一方面,作业需要消耗额外的 CPU/内存生成 Checkpoint,并且需要将 Checkpoint 数据存放在外部存储服务上,这意味着除了进行数据处理以外还需要付出额外的计算资源与存储空间成本;另一方面,所有的 Task 在进行容错恢复时都需要拉取 Checkpoint 数据,如果所依赖的存储服务压力较大而导致读取速度较慢,整个恢复过程将变得较为耗时。
对于批模式,一方面,当 Task 正常执行完毕所需时间较长时,由于重跑机制会从头开始处理,可能会导致恢复时间大幅增加。另一方面,如果 Task 的计算成本较高,重跑机制也会消耗较多的 CPU/内存资源。
综合来看,在状态较小且拓扑较为简单的情景中,流模式的容错代价往往小于批模式。在这种情况下,流模式的 Checkpoint 成本较低,只需要从最近的 Checkpoint 位点进行恢复,而批模式由于 Task 需要从头重跑,容错恢复时间相对较长。然而,当状态较大且拓扑复杂时,流模式的容错代价可能高于批模式。原因在于此时流模式的 Checkpoint 数据量较大,在生成 Checkpoint 时需要消耗较多的计算资源与存储空间成本,同时从 Checkpoint 恢复的过程也将较为耗时,这些代价可能会高于 Task 的重跑。
四、结论
在选择 Flink 作业的执行模式时,不能仅凭某一种规则进行“一刀切”式的判定,而应结合场景的需求和特点,具体问题具体分析,做出最佳选择。尽管传统经验认为实时性要求高的场景更适合流模式,而非实时处理的场景更适合批模式,但通过综合考量吞吐量、资源使用和容错代价等多个方面,我们可以得出更加精确的结论:
流模式适合的作业类型包括:实时性要求高的作业;非实时场景下,无状态且包含较多 Shuffle 步骤的作业;需要持续且稳定的数据处理能力的作业;状态较小、拓扑简单且要求较低容错代价的作业。
批模式适合的作业类型包括:非实时场景下,包含大量有状态算子的作业;需要高资源利用率的作业;状态较大、拓扑复杂且要求容错代价低的作业。
选择 Flink 作业的执行模式是一个综合考虑多方面因素的过程,开发者们可以根据不同的业务需求,在具体的应用场景中灵活选择流模式或批模式,从而达到符合需求的执行与资源利用效率。
欢迎大家加入 Flink Batch 交流钉钉群。本群旨在为 Flink Batch 爱好者提供一个交流技术和传递资讯的平台,在这里:
你可以掌握 Flink Batch 前沿的资讯,可以与 Flink 开发者及 Committer 面对面交流
Flink Batch 的问题集中解决,各位开发者及 Committer 及时解决你的 Blocker
“Flink Batch 交流群”群的钉钉群号: 34817520,也可以扫码加入
![](https://static001.geekbang.org/infoq/e0/e03443cf4a837fbdb53dca1f535967e9.webp?x-oss-process=image%2Fresize%2Cp_80%2Fformat%2Cpng)
更多内容
![](https://static001.geekbang.org/infoq/a3/a33f97129b55d8b82d711cf88fd42443.webp?x-oss-process=image%2Fresize%2Cp_80%2Fformat%2Cpng)
活动推荐
阿里云基于 Apache Flink 构建的企业级产品-实时计算 Flink 版现开启活动:新用户复制点击下方链接或者扫描二维码即可 0 元免费试用 Flink + Paimon实时计算 Flink 版(3000CU*小时,3 个月内)了解活动详情:https://free.aliyun.com/?utm_content=g_1000395379&productCode=sc
![](https://static001.geekbang.org/infoq/86/8683381ea8341651867cd2aa6f2e403c.webp?x-oss-process=image%2Fresize%2Cp_80%2Fformat%2Cpng)
版权声明: 本文为 InfoQ 作者【Apache Flink】的原创文章。
原文链接:【http://xie.infoq.cn/article/39dc48e95ce2150b96f476491】。文章转载请联系作者。
评论