Flink on YARN 依赖/JAR 包问题排查指南

适用问题:ClassNotFoundException、NoClassDefFoundError、NoSuchMethodError、ClassCastException、LinkageError、不同环境(本地/集群)表现不一致、在 TaskManager 上失败等。

Flink 作业运行时可能同时存在多套依赖来源:

  1. Flink 发行包自带 lib

位于 Flink 集群分发目录的 lib/(YARN 模式下会被分发到容器里)。

  1. yarn.provided.lib.dirs(父加载器可见的额外 lib)

通常用于放"大依赖/多作业共用依赖",作用类似集群级共享库。

  1. 作业 Jar(用户代码 Jar)

通过 flink run 提交的 jar;如果是 fat/uber jar,里面还携带第三方依赖。

  1. 插件(plugins/)

一般用于 connector/format 的插件化加载(不同版本隔离)。

核心点:Flink 默认 child-first(优先作业 jar),个别包会被强制 parent-first(Flink 自己的、日

志、部分 Java/Scala 等),并可通过 classloader.parent-first-patterns.additional 调整。

-D classloader.resolve-order=child-first(默认是child-first,不建议改为 parent-first)

-D classloader.parent-first-patterns.additional = okhttp3.,okio.,kotlin.

二、 先按异常类型分流(最快定位方向)

A. ClassNotFoundException / NoClassDefFoundError

含义:运行时找不到类。优先怀疑:

  • 依赖没带上(作业 jar 非 fat、provided 目录缺包)
  • 依赖拆分成多个 jar(例如 Kotlin/OkHttp/Okio),你只放了其中一部分
  • 提交命令参数(-C/-yD)或部署目录不一致,导致容器里没有对应 jar

结论倾向:缺依赖/类不可见。

B. NoSuchMethodError / IncompatibleClassChangeError

含义:类找到了,但版本/二进制签名不匹配。优先怀疑:

  • 同一个库出现两份不同版本(作业 jar + provided / Flink lib)
  • 依赖传递导致版本漂移(A 依赖 okhttp 4.9.3,B 依赖 okhttp 3.x)
  • shaded 与非 shaded 混用

结论倾向:版本冲突。

C. ClassCastException(尤其报"cannot be cast to ..."且类名相同)

含义:同名类被不同 ClassLoader 加载,两份"同类"互相不能 cast。优先怀疑:

  • 同一个 jar 在 parent(provided/lib)和 child(作业 jar)各一份 或 connector/plugin 与作业 jar 重复

结论倾向:类加载器隔离导致的重复类。

三、现场信息抓取(YARN 上先拿到"容器里到底有什么")

3.1 找到失败的容器日志

yarn logs -applicationId <appId> > app.log

或只抓某个 container:

yarn logs -applicationId <appId> -containerId <containerId>

重点看:

TaskManager 的 stderr/stdout(多数类问题发生在 TM)报错栈第一处 Caused by(最关键)

3.2 确认容器里加载了哪些 jar

在日志中搜索:

Classpath: / class path(不同版本可能打印位置不同)

Found jar / Adding jar / Using configuration 等关键词

如果日志不够,进入"增强日志"步骤(见第 五 节)。

四、快速自检清单(90% 的问题在这里)

4.1 你的依赖到底在哪里?
  • 作业 jar 是否是 fat jar?检查 jar 里是否有 BOOT-INF/lib(Spring Boot)或大量第三方包(jar tf xxx.jar | head)。
  • yarn.provided.lib.dirs 是否真正生效?配置是否在提交使用的 flink-conf.yaml 生效?是否指向 HDFS/本地且可被 YARN 访问?目录是否有读权限?
  • plugins/ 是否放了 connector(kafka、hudi、iceberg)?是否与作业 jar 重复?
4.2 依赖是否"成组"出现(常见坑)

很多库不是单 jar 就能跑,典型例子:

OkHttp 4.x:需要 Okio、Kotlin stdlib(且可能需要 jdk7/jdk8 扩展包,视版本而定)

Jackson:core / databind / annotations 版本需对齐

Netty:一套版本需对齐(Flink 自带,用户不要随便覆盖)

经验:如果用 provided 方式提供依赖,请按依赖树把传递依赖一起放齐,并保持版本一致。

五、开启类加载调试日志(定位"到底从哪个 jar 加载的")

在提交或配置中增加(不同日志框架版本可能是 log4j/log4j2,原则相同):

-Dlog4j.logger.org.apache.flink.runtime.classloading=DEBUG

你会在日志里看到类似:

  • 某某 ClassLoader 加载了 com.xxx.Foo,来源 jar 路径
  • 哪些 jar 被加入用户类路径

这一步可以直接回答:

  • 类究竟来自"作业 jar"还是 "provided/lib"
  • 是否出现一份类被加载了两次(两个不同 ClassLoader)

六、用"依赖树"确认应该有什么(本地就能做)

Maven

mvn -q dependency:tree > dep.tree.txt

针对某个库过滤:

mvn -q dependency:tree | grep -E "okhttp|okio|kotlin|jackson|netty"

Gradle

./gradlew dependencies --configuration runtimeClasspath > deps.txt

你要确认两件事:

  • 运行时依赖是否齐全(ClassNotFoundException常用,简称 CNF)
  • 同一 group/artifact 是否出现多个版本(冲突常用)

七、处理策略:缺依赖 vs 冲突(给出可选解)

7.1 缺依赖(CNF / NoClassDefFoundError)

优先推荐顺序:

  • 直接打 fat jar(最稳),用 shade/assembly 把运行时依赖都打进作业 jar(排除 Flink 自带依赖,如 flink-*, scala-*, slf4j/log4j 等)。
  • 或补齐 provided 目录依赖(成组补齐),不要只放一个 okhttp.jar,要把其传递依赖也放进去。
  • 校验 yarn.provided.lib.dirs 配置是否对当前 job 生效(常见是改了配置但提交用的是另一个 conf)。
7.2 版本冲突(NoSuchMethodError / IncompatibleClassChangeError)

可选处理:

  • 消除重复来源:不要同时在作业 jar 和 provided/flink lib 放同一依赖
  • 锁版本:用 dependencyManagement / Gradle constraints 固定版本
  • 必要时用 shading relocation:把你自己的三方库 relocate 到私有命名空间(例如 com.myjob.shaded.okhttp3...),避免和集群侧冲突
  • 很少数场景:用 classloader.parent-first-patterns.additional 强制 parent-first(谨慎使用,容易引入另一类冲突)
7.3 类加载器重复导致 ClassCastException

典型解决:

  • 确保同一个库只在一个"层级"出现:要么只在作业 jar,要么只在 provided/plugin
  • connector/plugin 与作业 jar 里不要重复放同款依赖
  • 必要时对重复库做 shading relocation
  • 只在本地 IDE 跑通,YARN 上 CNF。原因:本地 classpath 完整,YARN 容器缺 jar;或 provided 目录没生效/路径权限问题。
  • JM 正常,TM 报缺类。原因:用户 jar 分发到 TM 失败、或 TM 侧 classpath 不同、或动态加载的算子在 TM 初始化时报错。
  • 升级作业依赖后出现 NoSuchMethodError。原因:集群 lib/provided 中仍然是旧版本,child/parent 加载顺序导致混用。
  • OkHttp/Kotlin 相关。OkHttp 4.x 引入 Kotlin 生态依赖,provided 只放 okhttp 经常缺类;需要按依赖树补齐(kotlin-stdlib、okio、annotations 等),并注意版本对齐。

九、建议的落地规范(减少以后踩坑)

  • 明确约定:集群 lib/provided 放什么、作业 jar 放什么(二选一,尽量别混)
  • 作业构建时输出:
  1. dependency:tree(留档)
  2. 最终 jar 清单(jar tf 或构建报告)
  • 对"高频冲突库"建立黑名单/白名单:netty、jackson、kafka client、guava、protobuf、kotlin 等
  • 集群升级/依赖变更时同步更新 provided,并做回归测试
相关推荐
华农DrLai7 小时前
Spark SQL Catalyst 优化器详解
大数据·hive·sql·flink·spark
岁岁种桃花儿8 小时前
Flink从入门到上天系列第一篇:搭建第一个Flink程序
大数据·linux·flink·数据同步
Hello.Reader16 小时前
Flink ZooKeeper HA 实战原理、必配项、Kerberos、安全与稳定性调优
安全·zookeeper·flink
Hello.Reader20 小时前
Flink 使用 Amazon S3 读写、Checkpoint、插件选择与性能优化
大数据·flink
Hello.Reader21 小时前
Flink 对接 Google Cloud Storage(GCS)读写、Checkpoint、插件安装与生产配置指南
大数据·flink
Hello.Reader21 小时前
Flink Kubernetes HA(高可用)实战原理、前置条件、配置项与数据保留机制
贪心算法·flink·kubernetes
wending-Y1 天前
记录一次排查Flink一直重启的问题
大数据·flink
Hello.Reader1 天前
Flink 对接 Azure Blob Storage / ADLS Gen2:wasb:// 与 abfs://(读写、Checkpoint、插件与认证)
flink·flask·azure
Hello.Reader1 天前
Flink 文件系统通用配置默认文件系统与连接数限制实战
vue.js·flink·npm
Hello.Reader1 天前
Flink Plugins 机制隔离 ClassLoader、目录结构、FileSystem/Metric Reporter 实战与避坑
大数据·flink