it-roy-ru.com

java.sql.SQLException: не найден подходящий драйвер при загрузке DataFrame в Spark SQL

Я сталкиваюсь с очень странной проблемой при попытке загрузить JDBC DataFrame в Spark SQL. 

Я попробовал несколько кластеров Spark - YARN, автономный кластер и псевдораспределенный режим на моем ноутбуке. Это воспроизводимо как на Spark 1.3.0, так и на 1.3.1. Проблема возникает как в spark-Shell, так и при выполнении кода с spark-submit. Я пробовал драйверы MySQL и MS SQL JDBC без успеха.

Рассмотрим следующий пример:

val driver = "com.mysql.jdbc.Driver"
val url = "jdbc:mysql://localhost:3306/test"

val t1 = {
  sqlContext.load("jdbc", Map(
    "url" -> url,
    "driver" -> driver,
    "dbtable" -> "t1",
    "partitionColumn" -> "id",
    "lowerBound" -> "0",
    "upperBound" -> "100",
    "numPartitions" -> "50"
  ))
}

Пока все хорошо, схема разрешается правильно:

t1: org.Apache.spark.sql.DataFrame = [id: int, name: string]

Но когда я оцениваю DataFrame: 

t1.take(1)

Следующее исключение происходит:

15/04/29 01:56:44 WARN TaskSetManager: Lost task 0.0 in stage 0.0 (TID 0, 192.168.1.42): Java.sql.SQLException: No suitable driver found for jdbc:mysql://<hostname>:3306/test
    at Java.sql.DriverManager.getConnection(DriverManager.Java:689)
    at Java.sql.DriverManager.getConnection(DriverManager.Java:270)
    at org.Apache.spark.sql.jdbc.JDBCRDD$$anonfun$getConnector$1.apply(JDBCRDD.scala:158)
    at org.Apache.spark.sql.jdbc.JDBCRDD$$anonfun$getConnector$1.apply(JDBCRDD.scala:150)
    at org.Apache.spark.sql.jdbc.JDBCRDD$$anon$1.<init>(JDBCRDD.scala:317)
    at org.Apache.spark.sql.jdbc.JDBCRDD.compute(JDBCRDD.scala:309)
    at org.Apache.spark.rdd.RDD.computeOrReadCheckpoint(RDD.scala:277)
    at org.Apache.spark.rdd.RDD.iterator(RDD.scala:244)
    at org.Apache.spark.rdd.MapPartitionsRDD.compute(MapPartitionsRDD.scala:35)
    at org.Apache.spark.rdd.RDD.computeOrReadCheckpoint(RDD.scala:277)
    at org.Apache.spark.rdd.RDD.iterator(RDD.scala:244)
    at org.Apache.spark.scheduler.ResultTask.runTask(ResultTask.scala:61)
    at org.Apache.spark.scheduler.Task.run(Task.scala:64)
    at org.Apache.spark.executor.Executor$TaskRunner.run(Executor.scala:203)
    at Java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.Java:1142)
    at Java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.Java:617)
    at Java.lang.Thread.run(Thread.Java:745)

Когда я пытаюсь открыть соединение JDBC на исполнителя:

import Java.sql.DriverManager

sc.parallelize(0 until 2, 2).map { i =>
  Class.forName(driver)
  val conn = DriverManager.getConnection(url)
  conn.close()
  i
}.collect()

работает отлично:

res1: Array[Int] = Array(0, 1)

Когда я запускаю тот же код на локальном Spark, он тоже отлично работает:

scala> t1.take(1)
...
res0: Array[org.Apache.spark.sql.Row] = Array([1,one])

Я использую Spark, предварительно собранный с поддержкой Hadoop 2.4.

Самый простой способ воспроизвести проблему - запустить Spark в псевдораспределенном режиме с помощью скрипта start-all.sh и выполнить следующую команду:

/path/to/spark-Shell --master spark://<hostname>:7077 --jars /path/to/mysql-connector-Java-5.1.35.jar --driver-class-path /path/to/mysql-connector-Java-5.1.35.jar

Есть ли способ обойти это? Это выглядит как серьезная проблема, поэтому странно, что поиск в Google здесь не помогает.

10
Wildfire

Видимо об этой проблеме недавно сообщалось:

https://issues.Apache.org/jira/browse/SPARK-6913

Проблема в Java.sql.DriverManager, который не видит драйверы, загруженные ClassLoaders, кроме начальной загрузки ClassLoader.

В качестве временного решения можно добавить требуемые драйверы в загрузочный путь к классам исполнителей. 

ОБНОВЛЕНИЕ: этот запрос на удаление исправляет проблему: https://github.com/Apache/spark/pull/5782

ОБНОВЛЕНИЕ 2: исправление объединено в Spark 1.4

4
Wildfire

Для записи данных в MySQL

В spark 1.4.0 вы должны загрузить MySQL перед записью в него, потому что он загружает драйверы в функцию load, но не в функцию write ... Мы должны поместить jar на каждый рабочий узел и указать путь в spark-defaults.conf. файл на каждом узле . Эта проблема была исправлена ​​в spark 1.5.0

https://issues.Apache.org/jira/browse/SPARK-10036

3
Harish Pathak

Мы застряли на Spark 1.3 (Cloudera 5.4), поэтому я нашел этот вопрос и ответ Wildfire полезным, поскольку он позволил мне перестать биться головой об стену. 

Думаю, я поделюсь тем, как мы поместили драйвер в путь к загрузочному классу: мы просто скопировали его в /opt/cloudera/parcels/CDH-5.4.0-1.cdh5.4.0.p0.27/lib/Hive/lib на всех узлы.

1
Kevin Pauli

Я использую spark-1.6.1 с сервером SQL, но столкнулся с той же проблемой. Мне пришлось добавить библиотеку (sqljdbc-4.0.jar) в lib в строке экземпляра и ниже в файле conf/spark-dfault.conf.

spark.driver.extraClassPath lib/sqljdbc-4.0.jar

0
user3466407