最近写了一个用spark连接oracle,然后将mysql所有的表保存到hive中的程序,在本地eclipse里运行没有问题,想在集群上跑一下,看看在集群上性能如何,但是用spark-submit 提交程序时抛出一个异常Exception in thread “main” java.sql.SQLException: No suitable driver,一开始以为spark-submit提交时找不到oracle 驱动jar,折腾了半天才发现是代码问题。

1、猜测是否是缺失oracle驱动

由于在本地没有问题,所以不会想到是代码问题,根据提示想到的是spark-submit找不到oracle驱动,因为maven或sbt仓库里没有oracle驱动,在本地跑的时候,是将oracle驱动下载到本地,然后在eclipse设置build path就可以了。

但是我在spark-submit 里已经通过–jars 加载oracle驱动了:

spark-submit --class com.fm.bigdata.statistics.EntranceTest --master local target/scala-2.11/spark-gpanchor-statistics-assembly-0.1.jar

开始以为自己用法不对,但是上网搜了一下,发现就是这么用的~

然后尝试用–driver-class-path、–driver-library-path等都没成功。

2、sbt-assembly打包

网上查的sbt-assembly打包可以将所有依赖的jar包包括你写的代码全部打包在一起,于是尝试了一下

首先在项目目录中project/plugins.sbt添加

addSbtPlugin("com.eed3si9n" % "sbt-assembly" % "0.14.5")
resolvers += Resolver.url("bintray-sbt-plugins", url("http://dl.bintray.com/sbt/sbt-plugin-releases"))(Resolver.ivyStylePatterns)

但是这样执行sbt-assembly打包会报错,需要解决jar包冲突(deduplicate)问题

在项目的bulid.sbt里添加如下即可(只是其中一种解决策略,可根据自己项目实际情况自己设定)

assemblyMergeStrategy in assembly := {
    case m if m.toLowerCase.endsWith("manifest.mf") => MergeStrategy.discard
    case m if m.startsWith("META-INF") => MergeStrategy.discard
    case PathList("javax", "servlet", xs @ _*) => MergeStrategy.first
    case PathList("org", "apache", xs @ _*) => MergeStrategy.first
    case PathList("org", "jboss", xs @ _*) => MergeStrategy.first
    case "about.html"  => MergeStrategy.rename
    case "reference.conf" => MergeStrategy.concat
    case _ => MergeStrategy.first
}

这样就可以sbt-assembly进行打包了,发现这样打的jar包确实很大,用sbt package打的jar包大小1.48MB,sbt-assembly打的jar包大小194MB,将spark-scala-assembly-1.0.jar上传到服务器,然后执行submit,发现还是报同样的错,查看一下sbt-assembly日志,发现确实将oracle驱动加载上了~

3、真正原因

这样就猜想不是缺少mysql驱动,于是上网查了好多,偶然发现可能是代码问题,下面是我写的从mysql取数的部分代码

    spark.read
      .format("jdbc")
      .option("url", "jdbc:mysql://spero-gpanchor-service-dev-300df0fa.cn-shanghai-1.ads.aliyuncs.com:10018/spero_gpanchor_service_dev?useUnicode=true&characterEncoding=UTF-8")
      .option("dbtable", "spero_video_ads")
      .option("user", "user")
      .option("password", "passwd")
      .load()

写法和我之前写的spark连接mysql的写法是一样的

这样写在IDEA运行是没问题的,但是在spark-submit提交时是不行的,需要加上驱动信息

.option("driver", "com.mysql.jdbc.Driver")

results matching ""

    No results matching ""