
背景
高质量数据集项目中使用PyFlink作为引擎,使用java自定义flink source和sink,用于读取写入多模态文件,使用python实现flink算子,用于处理多模态文件,flink为2.1版本
现象
- flink算子使用python写的透传算子,不会oom
- flink算子使用python写的pdf抽取问答对算子,oom
- 并行度100,tm配置:slot=10 cpu=10c memory=8G oom
- 并行度100,tm配置:slot=10 cpu=10c memory=12G oom
排查过程
1. 确定进程
通过top发现java python进程内存占用都挺高
通过flinkUi发现jvm manager(python进程默认使用manager)内存占用也挺高
因为现象1故判断是是python进程内存泄露,是pdf抽取问答对算子问题,故参考:https://cloud.tencent.com/developer/article/1972101对该算子进行内存分析,发现并无内存泄露问题
再次持续观察flinkUi,虽然manager内存占用高,但无持续增长趋势,jvm内存持续增长
通过gcutil查看gc,jvm内存ygc频率高,每次ygc都有部分到老年代,在程序运行20分钟左右后,内存就全到老年代,gc不掉,由此判断java进程出现了内存泄露
1 | jstat -gcutil 1 2000 |

2. 分析内存
给pyflink添加jvm参数,导出堆文件
本项目使用的是pyFlinkOnK8s,在flinkConfigreation中添加:key:env.java.opts value:-XX:+HeapDumpOnOut0fMemoryError -XX:HeapDumpPath=k8s挂载路径使用MAT分析内存文件
- 查看Histogram,发现有大量的Mail StreamTask中的匿名类

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

- 在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次数,内存增长速率大幅减少
