K8s部署Zeppelin0.10.1+Spark3.2.1 Shuffle时Executor间通信失败修复
Spark on K8s (Zeppelin 0.10.1 + Spark 3.2.1 client模式) Shuffle通信故障定位与修复
根因定位优先级排序
先明确:你看到的Executor间Shuffle拉取连接关闭是次生故障,前置的Janino编译异常、Whole-stage codegen禁用才是核心触发点,不要一上来就抓包查网络,90%概率不是网络策略问题。
- 第一优先级排查:REPL动态类加载失败
日志里$line34105858122开头的类是Zeppelin Scala REPL为单元格内定义的自定义样例类动态生成的字节码,Spark 3.2.1 client模式跑在K8s上时,默认不会把这些REPL动态生成的类同步到独立运行的Executor Pod。
完整触发链路:- 执行含
group by的SQL时,Whole-stage codegen尝试生成全阶段Java代码,因为找不到REPL动态类的定义,Janino编译失败,触发codegen禁用告警,回退到非代码生成的普通执行路径 - 非代码生成路径下,Executor反序列化Shuffle数据块时需要加载这个REPL动态生成的样例类,直接抛
ClassNotFoundException/NoClassDefFoundError - 这个异常没被Shuffle服务的异常处理器捕获,直接关闭了Netty传输通道,远端Executor拉取Shuffle块时就会报连接被关闭的IOException,重试多少次都不会成功
- Driver和Executor通信正常是因为任务下发走独立的RPC通道,不涉及Shuffle数据反序列化加载REPL类的逻辑,所以不会报错
验证方法:翻Executor报错日志的前20行,肯定能找到对应$line开头类的类找不到异常,被后面的Netty IOException栈盖住了很容易漏看。
- 执行含
- 第二优先级排查:K8s网络策略
验证只需要2步,5分钟就能排除:- 进任意Executor Pod,用
curl http://<目标Executor Pod IP>:7337访问Shuffle服务端口,能通就直接排除网络问题 - 如果不通,检查对应Namespace下的NetworkPolicy是否放行带相同
spark-app-selector标签的Pod间7337端口TCP流量
- 进任意Executor Pod,用
- 第三优先级排查:序列化配置
检查是否开启了Kryo序列化但没有注册自定义样例类,这类问题报错栈会明确提示Kryo注册失败,不会先出Janino编译异常,优先级最低。
可落地修复方案
按生效速度、稳定性排序:
- 临时快速修复(无需重启集群,改完解释器配置即可生效)
在Zeppelin Spark解释器配置中增加以下参数:# 显式开启REPL动态类同步到Executor spark.repl.class.outputDir=/tmp/spark-repl-classes spark.files.useFetchCache=false spark.executor.userClassPathFirst=true # 临时规避Janino编译动态类失败问题,不需要改依赖包 spark.sql.codegen.wholeStage=false - 长期稳定修复(性能无损失)
- 替换Spark依赖中的Janino包为3.0.16版本(Spark 3.2.1官方匹配版本),解决Whole-stage codegen阶段无法识别REPL动态类的编译问题,不需要关闭codegen损失性能
- 在Spark K8s配置中开启自动类路径同步:
spark.kubernetes.executor.autoClasspath=true - 高频使用的自定义样例类、UDF直接打到Spark基础镜像中,完全规避REPL动态类分发的问题
- 网络策略兜底(仅当验证确实存在网络拦截时配置)
新增一条NetworkPolicy,放行同Spark作业Pod间的必要端口:apiVersion: networking.k8s.io/v1 kind: NetworkPolicy metadata: name: spark-shuffle-allow spec: podSelector: matchLabels: spark-app: zeppelin-spark-job ingress: - from: - podSelector: matchLabels: spark-app: zeppelin-spark-job ports: - protocol: TCP port: 7337 # Shuffle服务端口 - protocol: TCP port: 7078 # Driver RPC端口
修复验证步骤
- 先跑简单的测试SQL:
select col1, count(1) from test_table group by col1 limit 10 - 检查Executor日志中无
$line开头类的类找不到异常 - 确认Shuffle拉取无连接报错,任务执行成功后再跑全量业务SQL
内容的提问来源于stack exchange,提问作者dontoronto
相关产品推荐
相关产品推荐

