文章目录
- 现象
- 作业背景
- 分析
- 现象分析
- 类卸载条件
- MAT 分析
- 解决办法
- flink 官方提示
现象
通过flink 页面提交程序,多次提交后,jobmanager 报metaspace oom
作业背景
用户代码是flink 代码+Spring +nacos
分析
现象分析
从现象来看肯定是因为有的类没有被正确卸载导致的
类卸载条件
要卸载一个 Java 类,需要满足以下几个基本条件:
该类没有被任何引用对象所引用。也就是说,没有其他对象持有该类的引用。
该类的类加载器已经不再使用。如果一个类的类加载器还在使用,那么这个类就无法被卸载。
该类的 Class 对象已经从内存中被清除。只有当 Class 对象被从内存中移除,类的定义和字节码才算真正被卸载。
该类没有任何静态方法或静态变量被其他类所引用。如果有其他类持有该类的静态成员的引用,那么这个类也无法被卸载
MAT 分析
从MAT Duplicate Class 功能分析来看,确实是多个类被重复加载,从引用关系上来说可以看到重复的类被线程所引用,正常来说这些线程应该是正常结束的,然后用arthas 分析了下nacos 这个线程ClientWorker 是一个守护线程只有jobmanager 结束线程会会正常结束
排除了nacos,看现象还有类重复加载,继续分析,发现是log4j 注册了钩子 函数,导致的
我用简单的代码还原了钩子函数下这个问题,从mat 分析来看是一样的
private static String name = "xxxl";
public void launcher(String[] args) {
StreamExecutionEnvironment executionEnvironment = StreamExecutionEnvironment.getExecutionEnvironment();
executionEnvironment.socketTextStream("localhost", 9092).print();
try {
Runtime.getRuntime().addShutdownHook(new Thread(
new Runnable() {
@Override
public void run() {
System.out.println(name);
}
}
));
executionEnvironment.execute("aa");
} catch (Exception e) {
throw new RuntimeException(e);
}
}
解决办法
解决办法,因为作业代码不好修改,对于这种有spring那一套的实时作业程序来讲,不适合从页面提交,从客户端直接提交,不会有这个问题,为啥从客户端提交不会有这问题,因为从页面提交,实际上是在jobmanager 这个进程里去搞,相当于会把这个进程给污染了,从客户端来说,每次提交都交都是全新的环境。
这个和部署也有一定的关系,如果是application 和per-job 模式,每次都会有一个新的jobmanager,也不会有这问题,实际上生产用的是k8s部署,用的session mode 模式,就会有这个问题
flink 官方提示
其实flink 官方已经注意到了这个问题,给出了常见的原因和解决方案