[英]Apache Spark-SQL vs Sqoop benchmarking while transferring data from RDBMS to hdfs
我正在研究一个用例,我必须将数据从 RDBMS 传输到 HDFS。 我们已经使用 sqoop 对这个案例进行了基准测试,发现我们能够在 6-7 分钟内传输大约 20GB 的数据。
当我尝试使用 Spark SQL 时,性能非常低(1 Gb 的记录从 netezza 传输到 hdfs 需要 4 分钟)。 我正在尝试进行一些调整并提高其性能,但不太可能将其调整到 sqoop 级别(1 分钟内大约 3 Gb 的数据)。
我同意 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 与 spark sql 基准测试。请帮助理解这个问题。
您正在使用错误的工具来完成这项工作。
Sqoop 将启动一系列进程(在数据节点上),每个进程都会连接到您的数据库(请参阅 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")
在将数据写入最终文件之前重新分区数据。
val df3 = df2.repartition(10) //to reduce the shuffle
ORC 格式比 TEXT 更优化。 将最终输出写入 parquet/ORC。
df3.write.format("ORC").save("hdfs://Hostname/test")
@amitabh 虽然标记为答案,但我不同意。
一旦您在从 jdbc 读取数据时给出了对数据进行分区的谓词,spark 将为每个分区运行单独的任务。 在您的情况下,任务数不应为 14(您可以使用 spark UI 确认这一点)。
我注意到您使用 local 作为 master,它只会为执行程序提供 1 个核心。 因此不会有并行性。 这就是你的情况。
现在要获得与 sqoop 相同的吞吐量,您需要确保这些任务并行运行。 理论上,这可以通过以下方式完成: 1. 使用 14 个执行器,每个执行器具有 1 个核心 2. 使用 1 个执行器和 14 个核心(频谱的另一端)
通常,我会为每个执行程序使用 4-5 个内核。 因此,我使用 15/5= 3 个执行程序测试了性能(我添加了 1 到 14 个以考虑为在集群模式下运行的驱动程序使用 1 个内核)。 使用:sparkConf.set 中的 executor.cores、executor.instances 来使用配置。
如果这不会显着提高性能,那么接下来就是查看执行程序内存。
最后,我将调整应用程序逻辑以查看 mapRDD 大小、分区大小和 shuffle 大小。
我遇到了同样的问题,因为您使用的代码段不适用于分区。
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")
您可以通过以下方式检查在您的火花作业中创建的分区数
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-executors 3.--executor-cores 4. --executor-memory 5. --driver-memory 6. fetch-size
2,3,4 和 5 选项取决于您的集群配置,您可以在 spark ui 上监控您的 spark 作业。
以下解决方案帮助了我
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.write.format("parquet").save("hdfs_location")
Sqoop 和 Spark SQL 都使用 JDBC 连接从 RDBMS 引擎获取数据,但 Sqoop 在这方面有优势,因为它专门用于在 RDBMS 和 HDFS 之间迁移数据。
Sqoop 中可用的每个选项都经过微调,以便在进行数据摄取时获得最佳性能。
您可以从讨论控制映射器数量的选项 -m 开始。
这是从 RDBMS 并行获取数据所需的操作。 我可以在 Spark SQL 中做到吗? 当然可以,但开发人员需要处理 Sqoop 一直在自动处理的“多线程”。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.