You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Spark连接gRPC在AWS EMR报java.lang.VerifyError操作数栈溢出求助

问题分析

出现的java.lang.VerifyError: Operand stack overflow是因为shade过程中字节码被错误修改,JVM验证字节码时发现操作数栈超出限制。核心原因是过度shade(如inAll覆盖了Spark自带类)或依赖版本与Spark自带版本兼容性冲突导致字节码损坏。

解决方案

方案1:精准控制Shade范围

避免使用inAll(会对所有依赖的目标包重命名,包括Spark自带类,易导致字节码损坏),仅对项目自身引入的gRPC相关依赖应用shade规则:

assembly / assemblyShadeRules := Seq(
  // 仅shade项目引入的gRPC库
  ShadeRule.rename("io.grpc.**" -> "shade.io.grpc.@1")
    .inLibrary("io.grpc" % "grpc-netty" % "你的gRPC版本")
    .inLibrary("io.grpc" % "grpc-protobuf" % "你的gRPC版本")
    .inLibrary("io.grpc" % "grpc-stub" % "你的gRPC版本")
    .inProject,
  // 仅shade项目引入的netty
  ShadeRule.rename("io.netty.**" -> "shade.io.netty.@1")
    .inLibrary("io.netty" % "netty-all" % "你的netty版本")
    .inProject,
  // 仅shade项目引入的protobuf
  ShadeRule.rename("com.google.protobuf.**" -> "shade.com.google.protobuf.@1")
    .inLibrary("com.google.protobuf" % "protobuf-java" % "你的protobuf版本")
    .inProject,
  // 仅shade项目引入的guava
  ShadeRule.rename("com.google.common.**" -> "shade.com.google.common.@1")
    .inLibrary("com.google.guava" % "guava" % "你的guava版本")
    .inProject
)

同时在依赖声明中排除Spark自带的冲突包,避免重复打包:

libraryDependencies ++= Seq(
  "io.grpc" % "grpc-netty" % "你的gRPC版本" excludeAll(
    ExclusionRule(organization = "io.netty"),
    ExclusionRule(organization = "com.google.protobuf"),
    ExclusionRule(organization = "com.google.guava")
  ),
  "io.grpc" % "grpc-protobuf" % "你的gRPC版本" excludeAll(
    ExclusionRule(organization = "com.google.protobuf"),
    ExclusionRule(organization = "com.google.guava")
  ),
  // 其他依赖同理排除冲突包
)

方案2:匹配Spark自带依赖版本

Spark 3.1.1(EMR 6.3.1默认)自带的核心依赖版本:

  • Netty: 4.1.58.Final
  • Guava: 27.0-jre
  • Protobuf: 3.11.4

将项目中引入的gRPC、netty、protobuf、guava版本调整为与上述版本兼容的范围(如gRPC 1.40.0,兼容netty 4.1.x、protobuf 3.11.x),可大幅降低shade后的字节码兼容性问题。

方案3:跳过Shade,使用类加载优先级

若不想使用shade,可通过强制用户类优先加载来规避冲突:

  1. 打包时不做shade,仅打包自身代码和依赖(排除Spark自带的netty、protobuf、guava)。
  2. 提交作业时添加以下参数:
spark-submit \
  --class 你的主类全路径 \
  --conf spark.driver.userClassPathFirst=true \
  --conf spark.executor.userClassPathFirst=true \
  --exclude-packages io.netty,com.google.protobuf,com.google.common \
  --jars 你的jar包路径 \
  其他作业参数

注意:userClassPathFirst可能引发Spark内部依赖问题,需测试验证。

方案4:修复Shade字节码问题

若上述方法无效,可能是sbt-assembly对gRPC内部类处理不当,可添加额外规则确保关联类被正确重命名,并升级sbt-assembly版本:

  1. 更新project/plugins.sbt中的插件版本:
addSbtPlugin("com.eed3si9n" % "sbt-assembly" % "1.2.0")
  1. 补充shade规则:
assembly / assemblyShadeRules := Seq(
  ShadeRule.rename("io.grpc.**" -> "shade.io.grpc.@1").inAll,
  ShadeRule.rename("io.netty.**" -> "shade.io.netty.@1").inAll,
  ShadeRule.rename("com.google.protobuf.**" -> "shade.com.google.protobuf.@1").inAll,
  ShadeRule.rename("com.google.common.**" -> "shade.com.google.common.@1").inAll,
  // 对protobuf生成的自定义类也进行shade
  ShadeRule.rename("你的protobuf生成包路径.**" -> "shade.你的protobuf生成包路径.@1").inProject
)

内容的提问来源于stack exchange,提问作者Sudipta Kar

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.18 07:50:28