Apache Spark-SQL vs Sqoop бенчмаркинг при передаче данных из СУБД в hdfs

Я работаю над прецедентом, когда мне нужно передавать данные из СУБД в HDFS. Мы провели бенчмаркинг этого случая с помощью sqoop и выяснили, что мы можем передавать данные 20GB за 6-7 минут.

где, как и при попытке то же самое с Spark SQL, производительность очень низкая(1 Гб записей занимает 4 минуты для передачи из netezza в hdfs). Я пытаюсь сделать некоторую настройку и увеличить ее производительность, но вряд ли настроит ее на уровень sqoop(около 3 Гб данные за 1 мин).

Я согласен с тем, что spark в первую очередь является процессором, но мой главный вопрос заключается в том, что spark и sqoop используют драйвер JDBC внутренне, поэтому почему так много разницы в производительности(или, может быть, я что-то упускаю). Я размещаю свой код здесь.

object helloWorld {
  def main(args: Array[String]): Unit = {
    val conf = new SparkConf().setAppName("Netezza_Connection").setMaster("local")
    val sc= new SparkContext(conf)
    val sqlContext = new org.apache.spark.sql.hive.HiveContext(sc)
    sqlContext.read.format("jdbc").option("url","jdbc:netezza://hostname:port/dbname").option("dbtable","POC_TEST").option("user","user").option("password","password").option("driver","org.netezza.Driver").option("numPartitions","14").option("lowerBound","0").option("upperBound","13").option("partitionColumn", "id").option("fetchSize","100000").load().registerTempTable("POC")
    val df2 =sqlContext.sql("select * from POC")
    val partitioner= new org.apache.spark.HashPartitioner(14)
    val rdd=df2.rdd.map(x=>(String.valueOf(x.get(1)),x)).partitionBy(partitioner).values
    rdd.saveAsTextFile("hdfs://Hostname/test")
  }
}

Я проверил много других сообщений, но не смог получить четкого ответа на внутреннюю работу и настройку sqoop, и я не получил Sqoop vs spark sql benchmarking .Пожалуйста, помогите в понимание этой проблемы.

5 ответов


вы используете неправильные инструменты для работы.

Sqoop запустит множество процессов (на datanodes), которые будут подключаться к вашей базе данных (см. num-mapper), и каждый из них будет извлекать часть набора данных. Я не думаю, что вы можете достичь своего рода параллелизма чтения с Spark.

получить набор данных с помощью Sqoop, а затем обработать его с помощью Spark.


вы можете попробовать следующее:-

  1. чтение данных из netezza без каких-либо разделов и с увеличением fetch_size до миллиона.

    sqlContext.read.format("jdbc").option("url","jdbc:netezza://hostname:port/dbname").option("dbtable","POC_TEST").option("user","user").option("password","password").option("driver","org.netezza.Driver").option("fetchSize","1000000").load().registerTempTable("POC")
    
  2. repartition данные перед записью его в окончательный файл.

    val df3 = df2.repartition(10) //to reduce the shuffle 
    
  3. форматы ORC более оптимизированы, чем текст. Запишите конечный результат в parquet / ORC.

    df3.write.format("ORC").save("hdfs://Hostname/test")
    

@amitabh Хотя это и обозначено как ответ, я с ним не согласен.

Как только вы дадите предикат для разделения данных во время чтения из jdbc, spark будет запускать отдельные задачи для каждого раздела. В вашем случае ни одна из задач не должна быть 14 (u может подтвердить это с помощью Spark UI).

Я замечаю, что вы используете local как master, который предоставит только 1 ядро для исполнителей. Поэтому параллелизма не будет. Что и происходит в вашем случае.

теперь чтобы получить ту же пропускную способность, что и sqoop, необходимо убедиться, что эти задачи выполняются параллельно. Теоретически это можно сделать либо с помощью: 1. Через 14 исполнителей с 1 ядре 2. Использование 1 исполнителя с 14 ядрами (другой конец спектра)

обычно, я бы пошел с 4-5 ядер на исполнителя. Так что я тест производительности с 15/5= 3 исполнителей (я добавила 1 до 14 считать 1 ядро для водителя работающего в режиме clustor). Использование: исполнитель.ядро, исполнитель.случаи, в sparkConf.устанавливать играйте с конфигурациями.

Если это не значительно увеличивает производительность, следующее, что нужно было бы посмотреть на память исполнителя.

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


ниже решение помогло мне


var df=spark.read.format("jdbc").option("url"," "url").option("user","user").option("password","password").option("dbTable","dbTable").option("fetchSize","10000").load() df.registerTempTable("tempTable") var dfRepart=spark.sql("select * from tempTable distribute by primary_key") //this will repartition the data evenly

dfRepart.писать.формат("паркет").сохранить("hdfs_location")


у меня была та же проблема, потому что кусок кода не работает для раздела.

sqlContext.read.format("jdbc").option("url","jdbc:netezza://hostname:port/dbname").option("dbtable","POC_TEST").option("user","user").option("password","password").option("driver","org.netezza.Driver").option("numPartitions","14").option("lowerBound","0").option("upperBound","13").option("partitionColumn", "id").option("fetchSize","100000").load().registerTempTable("POC")

вы можете проверить количество разделов, созданных в вас spark job по

df.rdd.partitions.length

вы можете использовать следующий код для подключения дБ:

sqlContext.read.jdbc(url=db_url,
    table=tableName,
    columnName="ID",
    lowerBound=1L,
    upperBound=100000L,
    numPartitions=numPartitions,
    connectionProperties=connectionProperties) 

для оптимизации работы spark следующие параметры: 1. # разделов 2. -- num-исполнители 3.-- исполнитель-ядра 4. -- исполнитель-память 5. -- драйвер-память 6. fetch-size

2,3,4 и 5 варианты зависит от конфигурации кластера вы можете контролировать свою работу spark на Spark ui.