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.
вы можете попробовать следующее:-
-
чтение данных из 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")
-
repartition данные перед записью его в окончательный файл.
val df3 = df2.repartition(10) //to reduce the shuffle
-
форматы 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.