PyFlinkOOM
saber599

背景

高质量数据集项目中使用PyFlink作为引擎,使用java自定义flink source和sink,用于读取写入多模态文件,使用python实现flink算子,用于处理多模态文件,flink为2.1版本

现象

  1. flink算子使用python写的透传算子,不会oom
  2. flink算子使用python写的pdf抽取问答对算子,oom
    • 并行度100,tm配置:slot=10 cpu=10c memory=8G oom
    • 并行度100,tm配置:slot=10 cpu=10c memory=12G oom

排查过程

1. 确定进程

  1. 通过top发现java python进程内存占用都挺高

  2. 通过flinkUi发现jvm manager(python进程默认使用manager)内存占用也挺高

  3. 因为现象1故判断是是python进程内存泄露,是pdf抽取问答对算子问题,故参考:https://cloud.tencent.com/developer/article/1972101对该算子进行内存分析,发现并无内存泄露问题

  4. 再次持续观察flinkUi,虽然manager内存占用高,但无持续增长趋势,jvm内存持续增长

  5. 通过gcutil查看gc,jvm内存ygc频率高,每次ygc都有部分到老年代,在程序运行20分钟左右后,内存就全到老年代,gc不掉,由此判断java进程出现了内存泄露

1
jstat -gcutil 1 2000

截图

2. 分析内存

  1. 给pyflink添加jvm参数,导出堆文件
    本项目使用的是pyFlinkOnK8s,在flinkConfigreation中添加:key:env.java.opts value:-XX:+HeapDumpOnOut0fMemoryError -XX:HeapDumpPath=k8s挂载路径

  2. 使用MAT分析内存文件

    1. 查看Histogram,发现有大量的Mail StreamTask中的匿名类

    截图

    1. 查看dominator_tree,发现是TaskMailboxImpl持有的Mail

    截图

    1. 在dominator_tree中右键对象->List object->with outgoing referencesc查看Mail对象持有的引用,通过descriptionFormat和decriptionArgs定位代码位置

    截图

3. 分析代码

根据MAT的分析结果,能获取到几条有效信息:

  • 发现大量的对象都是Mail对象,且描述为”Timer callback for %s @ %d”
  • Mail对象中的decriptionArgs其中一个为AbstractPythonFunctionOperator中的ProcessingTimeCallback匿名类

截图

截图

截图

通过上述信息,最终定位:由配置python.fn-execution.bundle.time发送刷新缓存的Mail,配置过小则会生产>消费,存放Mail的队列数据过多,导致OOM

问题修复

最终定位原因为python.fn-execution.bundle.time配置为了1,由于该引擎是处理多模态数据,对数据的实时性没那么敏感,故而将python.fn-execution.bundle.time调整为10000,python.fn-execution.bundle.size设置为1,即数量为1或者10s刷新一次缓存

调整后,可以明显看到jvm gc次数,内存增长速率大幅减少

截图