Windows:
Introducing Stream Windows in Apache Flink
关于 NoClassDefFoundError, 稍有经验的开发应该都遇到过,比如下面这个异常:
1 | java.lang.NoClassDefFoundError: org/apache/commons/lang/exception/NestableRuntimeException |
ClassNotFoundException 是引起 NoClassDefFoundError 的最常见原因,常见于实际需要使用的依赖版本与应用依赖不一致,这个问题非常常见,但是估计大家都没注意 ClassNotFoundException 为什么会被转换为 NoClassDefFoundError, 在一次线上问题的排查过程中笔者查询了 JLS 中的类的详细初始化顺序 Detailed Initialization Procedure, 在此摘抄一段最核心的部分:
在 Spark、Flink 应用等场景下,经常会将业务代码构造为一个 Uber jar 提交至集群运行,在一次 Hive-UDF 的集成过程中,使用 Apache Maven Shade Plugin 进行 Uber jar 构建后,加载类时提示找不到类,笔者将该 Uber jar 拉取至本地解压后发现类是存在的,但错误日志仅提示找不到类,后经过反复排查,原来是 Jar 包签名问题导致,只是笔者遇到的场景并未提示签名问题导致难以排查。
1 | <filters> |
相关文档参考:
JAR File Specification
“Invalid signature file” when attempting to run a .jar
关于重定位类,笔者初次接触是在编写 Spark 应用时遇到,当时业务应用需要用到一个高版本的 guava 依赖,而 Spark 内置依赖了低版本的 guava, 根据 JVM 默认的类加载顺序,Spark 内置依赖的 guava 依赖优先于业务依赖的 guava 版本,导致业务应用出现找不到方法的异常,后通过 Relocating Classes 将指定的包名进行调整以规避同一个应用域中需要加载不同版本相同类名的问题。
最近编写 Flink 应用也遇到了类似的问题,Flink 官方文档给出了多种方案,其中也包括了上面提到的使用 maven-shade-plugin 对类进行重定位,也提到了 Flink 的反向类加载机制,可以参考下相关文档。
相关文档参考:
Debugging Classloading
业务方反馈某组应用偶现超时,超时时间为 2s, 大概一两天出现一次,经过排查,超时出现的时刻应用正在进行 FullGC, 触发原因为 Ergonomics, 该组应用未显式设置过 GC 收集器,Java 8 默认为 Parallel GC, 该收集器以吞吐量为目标,并不注重最大暂停时间,且根据之前的测试,在使用该收集器时即使设置了 -XX:MaxGCPauseMillis=
其实在 Oracle 官方文档 Available Collectors 对如何选择收集器已经有了明确的说明,如果响应时间比总体吞吐量更重要,并且垃圾收集暂停时间必须保持小于 1 秒,那么请使用 -XX:+UseConcMarkSweepGC 或者 -XX:+UseG1GC.
If response time is more important than overall throughput and garbage collection pauses must be kept shorter than approximately 1 second, then select the concurrent collector with -XX:+UseConcMarkSweepGC or -XX:+UseG1GC.
附一个查看当前 JVM 进程 JVM 参数的命令:
1 | jps -lvm |
相关文档参考:
Ergonomics
Available Collectors
Java Platform, Standard Edition HotSpot Virtual Machine Garbage Collection Tuning Guide
jps - Java Virtual Machine Process Status Tool
GCeasy