RocksDB是Flink中的一个状态后端,它允许作业的状态大于可用内存量,因为状态后端可以将状态溢出到本地磁盘。这意味着磁盘性能可能会影响使用RocksDB的Flink作业的性能。通过一个案例研究,本文说明了使用RocksDB的Flink作业的吞吐量下降问题,并演示了我们如何将底层磁盘的性能确定为根本原因。
作业和执行环境
我们处理的是一个典型的物联网(IoT)工作,它处理数百万台设备发出的事件流。每个事件都包含设备标识符(ID)、事件类型和生成事件时的时间戳。作业基于设备ID对流进行分区,并以状态存储从每个事件类型到接收到该类型事件时的最新时间戳的映射。可以有数百种事件类型。对于每个传入事件,作业需要从接收到的事件类型的状态读取时间戳,并将其与传入事件进行比较。如果传入的时间戳较新,它会更新状态中存储的时间戳。
作业运行在Amazon Elastic Kubernetes服务(EKS)集群上,该集群是使用官方AWS命令行工具eksctl创建的,具有所有默认设置。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 JVM选项启用了TaskManager JMX:
env.java.opts.taskmanager: >-
-Dcom.sun.management.jmxremote
-Dcom.sun.management.jmxremote.authenticate=false
-Dcom.sun.management.jmxremote.ssl=false
-Dcom.sun.management.jmxremote.local.only=false
-Dcom.sun.management.jmxremote.port=1099
-Dcom.sun.management.jmxremote.rmi.port=1099
-Djava.rmi.server.hostname=127.0.0.1
然后我们将一个本地运行的VisualVM连接到TaskManager上,并进行了CP