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 vs spark sqlベンチマークを取得しました。この問題の理解にご協力ください。
仕事に間違ったツールを使用しています。
Sqoopは、(データノード上で)多数のプロセスを起動し、それぞれがデータベースに接続し(num-mapperを参照)、それぞれがデータセットの一部を抽出します。 Sparkで一種の読み取り並列処理を実現できるとは思いません。
Sqoopでデータセットを取得し、Sparkで処理します。
次のことを試すことができます:-
パーティションを使用せず、fetch_sizeを100万に増やして、netezzaからデータを読み取ります。
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よりも最適化されています。最終出力を寄木細工/ ORCに書き込みます。
df3.write.format("ORC").save("hdfs://Hostname/test")
使用しているコードがパーティションで機能しないため、同じ問題が発生しました。
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 by
df.rdd.partitions.length
次のコードを使用してdbに接続できます。
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 -メモリ6.フェッチサイズ
2、3、4、および5のオプションは、クラスター構成によって異なります。spark job on spark ui。
以下の解決策は私を助けました
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")
@amitabh答えとしてマークされていますが、私はそれに同意しません。
Jdbcからの読み取り中にデータをパーティション化する述語を指定すると、sparkはパーティションごとに個別のタスクを実行します。あなたの場合、タスクの数は14でなければなりません(uはspark UIを使用してこれを確認できます)。
ローカルをマスターとして使用していることに気付きました。これは、エグゼキュータに1つのコアしか提供しません。したがって、並列処理はありません。それがあなたの場合に起こっていることです。
ここで、sqoopと同じスループットを得るには、これらのタスクが並行して実行されていることを確認する必要があります。理論的には、これは次のいずれかで実行できます。1。各1コアの14個のエグゼキュータを使用する2. 14コアの1個のエグゼキュータを使用する(スペクトルのもう一方の端)
通常、エグゼキュータごとに4〜5コアを使用します。そこで、15/5 = 3のエグゼキューターでパフォーマンスをテストします(クラスターモードで実行されているドライバーの1つのコアを検討するために1から14を追加しました)。構成を操作するには、sparkConf.setのexecutor.cores、executor.instancesを使用します。
これによってパフォーマンスが大幅に向上しない場合は、次はエグゼキュータのメモリを確認します。
最後に、アプリケーションロジックを微調整して、mapRDDサイズ、パーティションサイズ、およびシャッフルサイズを確認します。