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,可通过强制用户类优先加载来规避冲突:
- 打包时不做shade,仅打包自身代码和依赖(排除Spark自带的netty、protobuf、guava)。
- 提交作业时添加以下参数:
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版本:
- 更新
project/plugins.sbt中的插件版本:
addSbtPlugin("com.eed3si9n" % "sbt-assembly" % "1.2.0")
- 补充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
相关产品推荐
相关产品推荐

