2015-04-28 5 views
10

Sto riscontrando un problema molto strano quando provo a caricare JDBC DataFrame in Spark SQL.java.sql.SQLException: Nessun driver adatto trovato durante il caricamento di DataFrame in Spark SQL

Ho provato diversi cluster Spark: YARN, cluster autonomo e modalità pseudo distribuita sul mio laptop. È riproducibile su Spark 1.3.0 e 1.3.1. Il problema si verifica in entrambi spark-shell e durante l'esecuzione del codice con spark-submit. Ho provato i driver JDBC MS SQL MySQL & senza successo.

consideri seguente esempio:

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" 
)) 
} 

Fin qui tutto bene, lo schema viene risolto correttamente:

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

Ma quando valuto dataframe: si verifica

t1.take(1) 

seguente eccezione:

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) 

Quando provo ad aprire la connessione JDBC su esecutore:

import java.sql.DriverManager 

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

funziona perfettamente:

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

Quando eseguo lo stesso codice su Spark locali, funziona perfettamente anche:

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

Sto utilizzando Spark pre-costruito con supporto Hadoop 2.4.

Il modo più semplice per riprodurre il problema è quello di iniziare Spark in pseudo modalità distribuita con start-all.sh sceneggiatura ed eseguire il comando seguente:

/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 

C'è un modo per lavorare intorno a questo? Sembra un problema grave, quindi è strano che googling non aiuti qui.

risposta

4

A quanto pare questo problema è stato recentemente riportato:

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

Il problema è in java.sql.DriverManager che non vede i driver caricati dal ClassLoader diversi ClassLoader bootstrap.

Come soluzione temporanea è possibile aggiungere i driver necessari per l'avvio del percorso di classe degli executor.

AGGIORNAMENTO: Questa richiesta di pull risolve il problema: https://github.com/apache/spark/pull/5782

UPDATE 2: La correzione è fusa alla Spark 1.4

+0

Hey @Wildfire, Come avete fatto sulla modifica del percorso di classe di avvio degli esecutori? Ho provato a modificare il classpath del contenitore YARN per aggiungere il jar mysql-connector-java, ma non ha corretto l'errore. Grazie! – JKnight

+1

@JKnight Non riuscivo a capire come aggiungere il driver JDBC per avviare il classpath su YARN, quindi sto solo usando la build Spark con patch. – Wildfire

1

Siamo bloccati su Spark 1.3 (Cloudera 5.4) e così ho trovato questa domanda e la risposta di Wildfire utile dal momento che mi ha permesso di smettere di sbattere la testa contro il muro.

Pensavo di condividere come abbiamo ottenuto il driver nel classpath di avvio: l'abbiamo semplicemente copiato in /opt/cloudera/parcels/CDH-5.4.0-1.cdh5.4.0.p0.27/lib/hive/lib su tutti i nodi.

+0

Ciao, hai riavviato Cloudera dopo aver aggiunto il driver a quella cartella? grazie – SantiArias

+1

@SantiArias sì, credo che abbiamo riavviato il cluster. –

3

Per la scrittura dei dati MySQL

In scintilla 1.4.0, è necessario caricare MySQL prima di scrivere in esso perché carica piloti in funzione del carico, ma non sulla funzione di scrittura. Dobbiamo inserire jar su ogni nodo worker e impostare il percorso nel file spark-defaults.conf su ogni nodo. Questo problema è stato risolto in scintilla 1.5.0

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

0

Sto usando scintilla 1.6.1 con il server SQL, ancora affrontato lo stesso problema. Ho dovuto aggiungere la libreria (sqljdbc-4.0.jar) alla lib nell'istanza e sotto la riga nel file conf/spark-dfault.conf.

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