磁盘对 Flink 中 RocksDB 状态后端的影响:案例研究

RocksDB 在 Flink 中的性能问题分析

正如最近的博客文章所述,RocksDB 是 Flink 中的一个状态后端,它允许作业的状态大于可用内存量,因为状态后端可以将状态溢出到本地磁盘。这意味着磁盘性能可能会对使用 RocksDB 的 Flink 作业的性能产生影响。通过一个案例研究,这篇博文说明了使用 RocksDB 的 Flink 作业的吞吐量下降问题,并演示了我们如何将底层磁盘的性能确定为根本原因。

背景和问题描述

我们正在处理一个典型的物联网 (IoT) 作业,该作业处理从数百万台设备发出的事件流。每个事件都包含设备标识符 (ID)、事件类型以及事件生成时的时间戳。该作业根据设备 ID 对流进行分区,并在状态中存储从每个事件类型到接收到该类型事件时的最新时间戳的映射。事件类型可能有数百种。对于每个传入事件,作业需要从接收事件类型的状态读取时间戳,并将其与传入事件进行比较。如果传入的时间戳较新,它会更新状态中存储的时间戳。

该作业在使用官方 AWS 命令​​行工具 eksctl 创建的 Amazon Elastic Kubernetes Service (EKS) 集群上运行,并具有所有默认设置。 Flink TaskManager 分配有 1.5 个 CPU 核和 4 GB 内存。该作业使用 RocksDB 状态后端,该后端配置为使用 Flink 的托管内存。state.backend.rocksdb.localdir 配置选项未显式设置,因此默认情况下底层 EC2 实例根卷上的 /tmp 目录用于 RocksDB 运行状态(即工作状态)。

吞吐量下降问题的观察

这篇博文指出,该作业最初在 EKS 上运行良好。但一段时间后(几小时或几天,具体取决于传入事件)作业吞吐量突然大幅下降。该下降可以很容易地再现。吞吐量指标图表显示,在某一天的 23:50 后不久,从每秒超过 10k 个事件下降到每秒几百个事件。此外,使用保存点停止作业然后从中恢复并没有帮助:重启后作业吞吐量仍然很低。尽管当作业从空状态重新启动时恢复了高吞吐量,但这不是一个选择,因为(1)作业状态会丢失,(2)作业吞吐量会在较短的时间后再次下降。

性能问题的定位

通过检查CPU指标,我们发现当吞吐量下降时,TaskManager 容器的 CPU 利用率也会降低。由于TaskManager容器可能会使用更多的CPU资源,因此CPU使用率的减少在这里只是一个症状。TaskManager容器的内存使用率在吞吐量下降之前很长时间就达到了分配限制,并且在 23:50 左右没有明显变化。

为了进一步调查性能问题,我们启用了 TaskManager 的 JMX 监控,并使用 VisualVM 进行 CPU 采样。结果显示,93% 的 CPU 时间都被 threadUpdateState 消耗了,这是运行 operatorUpdateState 的线程,该线程读取并更新 RocksDB 中的状态。几乎所有的CPU时间都被本机方法 org.rocksdb.RocksDB.get() 占用。这表明作业在从 RocksDB 读取状态时遇到了瓶颈。

磁盘性能分析

为了深入了解 RocksDB 的性能问题,我们启用了 Flink RocksDB 指标。块缓存是在内存中缓存数据以供读取的地方。块缓存在作业启动后的前几分钟内迅速被填满,主要是状态条目。然而,这并不能完全解释在 23:50 左右吞吐量下降的原因。

我们继续检查根卷的磁盘指标。读取吞吐量下降至每秒约 230 次,写入吞吐量也出现类似的下降。检查磁盘每秒输入/输出操作数 (IOPS) 容量,我们发现默认情况下,使用 eksctl 创建的 EKS 集群中的每个 EC2 实例都是 am5.large 实例,并带有一个通用 (gp2) 弹性块存储 (EBS) 根卷。根卷的大小为 80GB,提供 240 IOPS 的基准速率。这表明作业在磁盘 IO 上遇到了瓶颈。一开始能够实现更高 IOPS 的原因是 AWS 为每个 gp2 卷提供了初始 I/O 信用来维持突发 IO 请求。然而,初始 I/O 积分耗尽后,问题就出现了。

解决方案

为了解决性能问题,我们建议附加具有高 IOPS 率的专用卷,如 gp3 或 io1/io2 卷,并将 Flink 配置 state.backend.rocksdb.localdir 设置为该卷上的目录。需要注意的是,RocksDB 本机指标在默认情况下处于禁用状态,因为它们可能会对作业性能产生负面影响。但是在你面临性能问题时,启用这些指标可以帮助你更好地了解 RocksDB 的内部行为,以便更好地诊断和优化问题。

要实施这个解决方案,你可以按照以下步骤进行操作:

  1. 创建高性能的磁盘卷
    • 使用 AWS 控制台或 AWS 命令行工具创建一个 gp3 或 io1/io2 卷,它提供足够的 IOPS 来支持你的作业需求。你可以根据作业的负载情况来选择适当的磁盘类型和大小。
  2. 将 RocksDB 目录配置到新卷上
    • 在 Flink 配置中,将 state.backend.rocksdb.localdir 配置选项设置为新创建的高性能卷的挂载路径。这将使 RocksDB 在新卷上运行,并获得更高的磁盘性能。
  3. 启用 RocksDB 指标(可选):
    • 如果你想深入了解 RocksDB 的性能状况,你可以在 Flink 配置中启用 RocksDB 本机指标。这些指标将提供更多关于 RocksDB 内部运行情况的信息,帮助你更好地监视和优化作业。
  4. 重新部署作业
    • 在进行了上述更改后,重新部署你的 Flink 作业。确保作业配置正确地指向新的 RocksDB 目录,并验证作业在新磁盘上运行。
  5. 监控和调整
    • 监控你的作业性能,特别是 CPU 利用率、磁盘 IOPS 和延迟等指标。根据观察到的情况,你可能需要调整作业配置、磁盘类型或作业规模来进一步优化性能。

总之,通过将 RocksDB 目录配置到高性能的磁盘卷上,你可以显著改善 Flink 作业的性能,并避免在处理大量数据时出现吞吐量下降的问题。同时,启用 RocksDB 指标可以让你更深入地了解 RocksDB 在作业中的行为,从而更好地优化和监控作业性能。

关注公众号“大模型全栈程序员”回复“大数据面试”获取800页左右大数据面试宝典 ,回复“大数据”获取多本大数据电子书

关注公众号“大模型全栈程序员”回复“小程序”获取1000个小程序打包源码。更多免费资源在http://www.gitweixin.com/?p=2627