Spark集群模式运行MongoPartition出现ClassNotFoundException,本地正常如何解决?
核心原因说明
本地运行时Spark所有组件共享同一个JVM,驱动端存在依赖即可正常执行;集群模式下Driver与Executor运行在独立JVM环境,默认仅分发用户业务代码Jar,第三方依赖不会自动同步到Executor节点,同时你当前的依赖配置本身存在缺失和版本冲突问题,共同导致了报错。
修正依赖配置
你当前的build.sbt仅引入了MongoDB原生Java驱动,报错缺失的MongoPartition类属于Mongo-Spark连接器包,并不在原生驱动中,同时你的驱动版本存在混用问题,直接替换为如下配置即可:
// 引入Mongo-Spark连接器,自动传递匹配版本的MongoDB驱动,无需单独引入驱动包 libraryDependencies += "org.mongodb.spark" %% "mongo-spark-connector" % "3.0.1" // Spark本身提供的依赖设置为provided,避免打包冲突 libraryDependencies += "org.apache.spark" %% "spark-sql" % "3.0.1" % Provided
注意:Spark版本要和连接器版本匹配,3.0.x版本Spark对应3.0.x版本的Mongo-Spark连接器,Scala版本也要和集群Spark使用的Scala版本一致
方案1:打胖包直接提交(最稳定,推荐)
将所有第三方依赖和业务代码打包为一个独立的Jar包,提交时自动全量分发到所有Executor节点:
- 在
project/plugins.sbt文件中添加sbt-assembly插件:
addSbtPlugin("com.eed3si9n" % "sbt-assembly" % "0.15.0")
注意插件版本和你使用的sbt版本匹配
2. 执行sbt assembly命令,即可在target/scala-xxx/目录下生成包含所有依赖的胖Jar包
3. 直接使用该Jar包通过spark-submit提交即可,无需额外配置依赖参数
方案2:提交时动态指定依赖
如果不想打胖包,且你的Docker集群所有节点可以访问Maven中央仓库,可在提交命令中通过参数指定依赖:
spark-submit \ --class 你的主类全限定名 \ --master spark://集群Master节点地址:7077 \ --packages org.mongodb.spark:mongo-spark-connector_2.12:3.0.1 \ 你的业务代码Jar包路径.jar
不要在SparkSession代码中配置spark.jars.packages,提交命令的参数优先级更高,不会被集群默认配置覆盖
方案3:预安装依赖到集群镜像(适合长期频繁使用Mongo连接器的场景)
直接将Mongo-Spark连接器及对应依赖包复制到所有Spark节点的$SPARK_HOME/jars目录,你可以自定义Spark Docker镜像,在构建时将依赖包加入该目录,之后所有提交的任务都可以直接使用Mongo连接器,无需每次提交时携带依赖。
内容的提问来源于stack exchange,提问作者Shantanu Gupta

