[英]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.