チューニングのスパーク(1)

スパークで次のチューニング項目は、公式からのいくつかは、他のエンジニアからのいくつかは、それらのいくつかは、私自身の要約です。

基本的な概念と原則

      まず、基本的な概念と原則スパークのいくつか、質問のうちそれ以外の場合は、システムのパフォーマンスチューニングをクリアするには:

  •       Nワーカー上記並列内の各ホストは、M個の並列実行部の各々以下ワーカーは、タスクエグゼキュータは、実行するために、上記に割り当てられます。並列タスク遭遇シャッフルを走行停止のように、それは国境を上演することを意味し、ので、ステージはフェンスのように、シャッフル、シャッフルである内側段が並列で実行中のタスクのセットを意味し、表示することはできません。
  •       コアCPUの数は、各エグゼキュータは、コアの一つ以上を占めることができる、CPUの使用率が観察された変化を介してコンピューティングリソースの使用を理解することができ、例えば、廃棄物の非常に一般的なタイプは、エグゼキュータである複数のコアを占めるが、ホスト(executorが常にマルチコアの性能をフルに活用しないと)以下、よりエグゼキュータの労働者を加えながら、この時間は、executorが少ないコアを取り、それを考慮すること、または総CPU使用率が高くありませんエグゼキュータ上記より労働者が増加し、それによってCPUの使用率を増加させる、並列実行の数を増加させます。しかし、増加エグゼキュータは、マシンのメモリがよりエグゼキュータ、メモリの少ない各エグゼキュータに割り当てられているため、状況あまりにも多くのデータ流出事故でも、メモリのうち上で行われるように、良好なメモリ消費を考慮する必要があります。
  •       並列パーティション、パーティションは各データ処理タスクのみつのパーティション、データ数を意味し、この値が小さすぎるメモリ圧力で、その結果、各スライスの多すぎるデータ量につながる、または多数のコンピューティングパワーは、エグゼキュータできないであろう十分なアクセス;しかし、もしあまりにも多くの断片化につながると効率が低下します。操作のアクションタイプを実行する(ようなさまざまな操作を軽減)する場合、パーティションの数は最大の親RDDいずれかを選択します。RDDクラスで動作して削減する時間である並列処理を参照し、デフォルトの数値parititionリターンデータ(マップ、パーティション番号は、一般的に、より大きな親RDDから撮影するだけでなく、シャッフルを伴わない場合の動作の種類を実行したがって、この並列処理パラメータ)は効果がありません。したがって、これら二つの概念は密接に関連して、アクションのモードが実際に統一され、データの断片化に関連しています。あなたはspark.default.parallelismによって断片のデフォルト数を設定することができ、そして多くの操作は、明示的に制御断片の特定の数にRDDパーティションパラメータを指定することができます。
  •       これらの2つの原則の上には、ハードウェアやタスクに基づいて異なる値を選択するためにシンプルですが、非常に重要なようです。ユニバーサル設定をしたいことは現実的ではありません。このいくつかの例を見てください:(1)練習走行EMRスパークジョブは、いくつかは非常にゆっくりと、CPUの使用率が低いビュー、我々はと一緒に、エグゼキュータ、数の執行並列増加あたりの占有CPUコアの数を削減しようとしますフラグメンテーションが増加すると、CPU使用率の全体的な増加、より高速なデータ処理を行います。(2)また、並列実行部の数を低減しつつ、同一のメモリリソースがエグゼキュータの少ない数に割り当てられるように、我々はむしろ、それによって各データのサイズを縮小、断片の数を増加させるジョブメモリのオーバーフローを見つけることは容易です各タスクに割り当てられたメモリを増加させるので、速度が少し遅く、しかしOOM強いよりも良いことができます。(3)データの量は、唯一の最も原始的な入力が比較的小さい場合、この状況は、一般的に気付くことができ、ファイルの断片化を減らす生成小さなファイルが多数なので、マルチタスクを作成する必要がありますが、非常にまれであるが、プロセスは、このようなアプリケーションやreduceByフィルタ、データの大幅な削減と、動作中で後ならば、これはめったに非効率性に気づいていません。
  •       最後に、変更および構成パラメータを持つことを追加し、パフォーマンスのボトルネックが変更され、問題を分析する際にすることを忘れないでください。そのような性能は増加し始めている場合、各マシン上に展開エグゼキュータの数を増やすようにするだけでなく、平均CPU使用率が増加していることが観察され、しかし、単一のマシン上でより多くのエグゼキュータ、パフォーマンスの低下など数のエグゼキュータとして、メモリの量は、各エグゼキュータに割り当てられ、ディスクために、より多くのデータに対する流出は、天然の性能を劣化させる、少なくダイレクトメモリ動作を減少させます。

      ここでは、このような直感的な例に、現在のCPU使用率の合計は高くありません。


しかし、上記の原理に従った調整後、後、大幅に見つかった全体的な使用率、CPUを増やすことができます。


第二に、我々は多くの場合、設定を変更するには、パフォーマンス・チューニングに関与している、3つの一般的な構成はお互いを置き換えることができ、いくつかの設定パラメータが、内部のスパークでありますが、ベストプラクティスとして、やはり異なる構成を使用して、さまざまな状況に従ってくださいする必要があります。
  1. 環境変数の設定、および環境は主にこのように使用され、ハードウェア関連の設定。
  2. コマンドラインパラメータは、このアプローチは主に変更し、ダブルダッシュで始まります操作パラメータの異なる時間に使用されます。
  3. 内部コード(例えば、Scalaのような)明示的に設定(SparkConfオブジェクト)は、そのような構成は、一般的に変更しない、典型的には、アプリケーション・レベルの構成です。

構成の具体例。スレーブおよびワーカー・エグゼキュータとの比率を調整,. 私たちはしばしば、単純に二つの方法、その後、並列実行者の数を調整する必要があります。

  •       1.必ず各ワーカーの実行プログラム内で実行するが、単一のスレーブ作業者の平行調整の数。例えば、SPARK_WORKER_INSTANCESは、各スレーブワーカーの数を設定することができ、そのような変化2などの時間のパラメータを変更する際に、両者を可能にするように、各作業者が、コアの元の半分を使用するように、対応する値SPARK_WORKER_CORESを設定してください一緒に作業員の仕事。
  •       常に2.各スレーブ内でのみ従業員を配備するが、労働者の中に複数のエグゼキュータを展開。我々この調整の枠組みの中で使用される典型的なアプローチのみワーカーホストを実行する変化の糸キュータ量を、達成された後、ホストCPUコアのNにspark.executor.coresを設定し、また提供ホストはNエグゼキュータを開始できるように、N個の点のうちの1つに割り当てスパークspark.executor.memoryは、ホスト上のメモリを算出します。

      別のMRの枠組みの中でいくつかの構成は、/ツールは、このようないくつかのパラメータのYARNのデフォルト値が異なると、同じではありません、それは注意が必要です。

明確に基づいてこれらの事の後、主なポイントのパフォーマンスチューニングを参照してください一つずつ来ます。

メモリ

メモリー・チューニング、Javaオブジェクトは、元のデータであっても、より多くのスペース2〜5倍になります。メモリ消費量の物体を検出するための最良の方法は、その後、RDDを作成してキャッシュに内部に移動し、上記UIストレージの変化を見ることである。もちろん、SizeEstimatorを推定するために使用することができます。使用-XX:+ UseCompressedOops圧縮オプションポインタ(4バイトに8バイト)。心はそれを明確にするメモリコピーにデータの大きなブロック - APIの呼び出しが収集するときなどに注意する必要があります。また、少なすぎる予約した場合、バッファキャッシュのOSを含むオペレーティングシステムにはいくつかのメモリ、例えば20%を保存するには、このエラーが表示されます。

「必要なエグゼキュータのメモリ(235520 + 23552メガバイト)は、このクラスタの最大しきい値(241664メガバイト)を超えています!「yarn.scheduler.maximum割り当て-MB」の値を増やしてください。」

それとも、単にそのような間違いが、メモリ不足の問題が残っているが、このようないくつかの警告、存在しません。

「16/01/13夜11時54分48秒は、scheduler.TaskSchedulerImplをWARN:初期の仕事は、すべてのリソースを受け入れていません。「労働者が登録されていることを確認するためにクラスタUIを確認し、十分なメモリを持っています

時には、このようなログが表示されていないが、なぜ情報の損失は明らかではないエグゼキュータのいくつかを見るために:

「スレッドの例外 『メイン』 org.apache.spark.SparkException:ジョブによるステージ障害のために中止さ:段階17.0(TID 1257、IP-10から184にロストタスク12.3:タスク12を段階17.0には、最新の障害が4回失敗しました-192-56.ec2.internal):ExecutorLostFailure(エグゼキュータ79が失われました)」

メモリ使用量の作業を軽減します。いくつかのケースでは、特に、このようなシャッフルは、sortByKey、groupByKey、reduceByKeyとして、発生し、内部のメモリに巨大なハッシュテーブルを構築するために、他の参加時のように、メモリを消費するタスクを減らします。一つの解決策は、各タスクの入力サイズを相応に低減されるように、並列処理のレベルを増加させることです。また、パフォーマンスを向上していない、また、メモリの上限が設定されているシャッフルに注意を払う、そして時には十分なメモリがありますが、シャッフルメモリが十分ではありません。私たちは、データと他の操作の多くに参加すると、多くの場合、コンフィギュレーションの50%のエグゼキュータにメモリ制限をシャッフルします。

その元の入力の大きさに注意し、常に多くの操作が完了全集内部メモリ内の特定のデータを必要があり、その後、並列処理は、パーティションの値を大きくすると、非常に小さなメモリフットプリントを削減することができます難しいことではありません。我々はいくつかのパフォーマンスの低下にもOOMの問題は、これら2つのパラメータを軽減することが困難な変更することです会いました。しかし、それは、各マシンのメモリを解決するためのメモリの量を増加させることによって増加、または直接または間接的に、マシンの数を増やすことができます。

EC2のマシンタイプは、あなたが(テストによって明らかでよい)、ボトルネックをクリアしたいときに我々が遭遇するような、選択された後者の高価よりも、元の電源と同等の計算、r3.8のXLARGEとC 3-8のXLARGEの選択肢を使用することです50%が、メモリは5倍、後者です。

そうすることの利点は、それらを使用しない場合に加えて、キャッシュなどのRDDのAPIのいくつかは、持続、内部のデータメモリに明確ではない強制されます。

 

CPU

並列処理のレベル。デフォルトのパーティションの数が指定された場合の動作の種類が行われた削減、将来的にはそれを指定します。このパラメータは、通常、実際のプロジェクトである必要不可欠であり、一般的に入力し、各エグゼキュータのメモリサイズに基づいて決定する必要があります。平行または属性のレベルは、一般的に言えば、平行spark.default.parallelismレベルを変更するために提供され、割り当てられたCPUコアの各々は、2-3タスクとすることができます。

CPUコアのアクセス・モードは、共有または排他されます。すなわち、CPUコアは、同じホストまたは分割して排他的にエグゼキュータを共有しています。例えば、CPUコア32、展開2つの執行、総メモリ50Gのマシン上の総リソースは、その後の方法は、このため、20Gに、16 spark.executor.memory spark.executor.coresに配置されていますメモリの制限は、このマシンは、各使用20Gメモリ、及び「ソブリン」16 CPUコアリソースの各使用上の2つのエグゼキュータを展開する;同じ前提で、メモリリソースだけでなく、2でき32コアの「共有」キュータ。私のテストによると、わずかに良いパフォーマンスを排他モードと共有モード。

GCチューニング。GC情報を印刷:-verbose:gcを-XX:+ PrintGCDetails -XX:+ PrintGCTimeStampsを。メモリの40%のみが作成された空間オブジェクトとして使用することができるように、RDDキャッシュとして使用することができますエグゼキュータメモリのデフォルトの60%を覚えて、これはspark.storage.memoryFractionを設定することで変更することができます。多くの小さなオブジェクトがある場合に作成されますが、これらのオブジェクトは、不完全なGCの過程で回収することができ、その後、エデンエリアは確かに参考になります高めます。HDFSからデータをコピーするタスクがある場合は、単純なメモリ消費量の推定式がある - などHDFSのブロックサイズとしては64メガバイト、作業領域で、その後4つのタスクデータのコピー、および3倍に増加するブロックサイズを解凍、見積もりがありますメモリ消費量は次のとおりです。4 * 3 *の64メガバイト また、仕事はこのような問題に遭遇しました:GCデフォルトの限界場合があり、デフォルトのGC時間は、CPU時間の2%以上ではなく、オブジェクトの作成の多数は(それはスパークに表示されるように簡単であれば、コードパターンがRDDです次のRDD)を回し、それはそうそこに、GCの多くの時間につながる「OutOfMemoryErrorが発生する:GCオーバーヘッドの制限を超えて」、このために、あなたは-XXを設定することができます。それをオフに-UseGCOverheadLimit。

そして、送信シーケンス

データシリアライゼーションは、デフォルトのJava直列化を使用して、プログラマが最も精通しているが、貧しい人々よりも、パフォーマンス、パフォーマンス・スペース。別のオプションは、より速く、より高い圧縮率Kryoシリアライゼーションですが、任意のクラスのシリアル化をサポートしていません。この比率が高い場合、UIは、占有コストの合計時間系列の割合で見ることができるスパーク、あなたはメモリ使用量とシリアライズの最適化を検討することができます。

大規模な変数の番組。タスクの静的ラージオブジェクトを使用する場合は、それが出て放送することができます。スパークは、それはやる価値20キロバイトを超えた場合、一般的に言えば、サイズ、シリアライズを印刷します。一般的なシナリオは、大きなテーブルには小さなテーブルを結合することで、小さなテーブルの放送後、データは静かに滞在し、各ノード間で大きなテーブルFengpaoを必要としない地域や他の小さなテーブルだけで結構で放送。

データの局所性。データとコードデータよりも通常より良いコードに対処するために一緒に置かれるために、より小さくなるように、とても速くどこでも可能にするコード。データ局所性と室内空間密接度のデータ処理コード:PROCESS_LOCAL(同じJVM)、NODE_LOCAL(同一ノード、例えばHDFS上のデータとして、同じノード内のコードを)、NO_PREF、RACK_LOCAL(ありません同じサーバ、同じラック内)、ANY。上記アイドルエグゼキュータで未処理のデータが存在しない場合はもちろん、最高最低の優先度に、しかし、その後、2つのオプションがあります。

  • (1)いずれかのように、今日の引退と「ローカル」データとしてプロセスを座って忙しいとしてCPU、
  • (2)等の遠隔データ処理に直接対向タスクを開始していません。

これはCPUがビジー状態の場合(1)、停止しない、すなわち政策しばらく(spark.locality)を待つことになるデフォルトのスパークを発生した場合、それは政策を実行します(2)。

ラージオブジェクトへのコードの参照。タスク内の大きなオブジェクトを参照する場合、それがパフォーマンスの問題を引き起こして、各ノードまでのタスクにシリアライズされますので、注意します。限りシリアル化プロセスが例外をスローしないように、実際には参照オブジェクトのシリアル化の問題はほとんどの人に注意を払っていません。これは確かに大きなオブジェクトが必要であるならば、我々としても良いRDDにそれを回すかもしれません。ほとんどの時間、ラージオブジェクトのシリアル化の動作のために無意識のうちに発生した、またはそのような私たちのプロジェクトでは、このようなコードの一部として、期待を超えています:

 
 
  1. EET 地図R => {
  2. println BackfillTypeIndex
  3. })

実際には、これに相当します。

 
 
  1. EET 地図R => {
  2. println これBackfillTypeIndex
  3. })

この本を過小評価してはいけない、時にはそれがシリアライズは非常に大きなオーバーヘッドがあるのです。

このような問題のために、最も直接的な解決策の一つは、以下のとおりです。

 
 
  1. ヴァルdereferencedVariable = これBackfillTypeIndex
  2. RDD マップR => printlnをdereferencedVariable ))// "これは"シリアル化されていません

関連して、ノートには、大きなオブジェクトのためのトラップのシーケンスから除外非常に便利ですされる、シリアライズさではありません特定の変数を識別するために使用さ@Transient。また、時々小さなケースクラスは木から来るかもしれない、クラス間の継承階層関係に注意してください。

読み取りと書き込みのファイル

ファイルストレージを最適化して読みます。例えば、いくつかの例、もしほんの数の列、およびのrcfileの形式を使用するために、このような寄木細工が大幅にファイルを読み込むのコストを削減します。また、HDFSまたはS3のファイルに格納されているが、より適切な形態は、より高い圧縮率形式として、状況に応じて適宜選択することができます。加えて、特にシャッフルケースの特に多数の、そのようなメモリの50Gの合計として、オペレーティングシステムのバッファキャッシュとしてオペレーティング・システムに追加のメモリの特定の量を残して検討し、40Gまで割り当てるJVMは、より多くのビット。

ファイルの断片化。上記の例では断片化された形態、サフィックスpartXXに格納されているS3ファイルをサポートします。多くの部分に合体設定するために使用される方法は、並列処理のレベルに調整されるか、または整数倍の読み取りおよび書き込み性能を向上させることができます。しかし、良いではありませんが低すぎる低すぎる高すぎるが並列S3に読み書きする能力をフルに活用することができない、それは合併前、小さなファイルのためにあまりにも高く、その接続設定時間コストああは、読み取りと書き込みまた、簡単にスロットルを超えています。

タスク

投機のスパーク。spark.speculationや他のいくつかの関連オプションを設定することにより、スパークが特に遅いいくつかのタスクを実行するための時間を見つけたことができ、それは、完了を待たずに再実行することができ、最終的に同じタスクは限り実行があるとして終わって、その後、最速結果が採用される実行終了。

シャッフルを減らします。実際には、スパークは、多くの場合、すぐに計算しますが、上記のオーバーヘッドとネットワークIOの多くを費やし、そしてシャッフルは、古典的です。例えば、(K、V1)に参加(K場合 、V2)=>(kは、V3)、 次いで、このような状況があるため、どのノードのパーティションに参加する必要があるため、非常に優れたスパークが最適化され、実際に、迅速に完了ジョイン、結果は同じノード(一連の動作は、内部同じステージ上にあってもよい)です。データ構造がするように設計されている場合ただし、(OBJ1)に参加(OBJ2)=を >(OBJ3)、 もはや同じありますので、ジョイン条件obj1.column1 == obj2.column1は、多くの場合、この時間をシャッフルすることを余儀なくされなかったの同じノードの強度に関するデータを確実にするキー。ケースでシャッフルする前にデータのサイズを小さくすることが可能な限りをシャッフルしなければならない、などの例は、これを避けるgroupByKey以下からの画像の次の比較音声スパークサミット2013年代に同じことについて話して、:


配分。動作時のデータのビッグ、時には少量の、あまりにも多くのパーティションが存在する場合、パーティションの株式の数を適切に選択する多くの小さなタスクにつながったとの宇宙ミッションを作る。必要なときに、コンピューティングリソースへの少なすぎるのリードは、フルに活用することができない場合、再分割を使用することができます調整が、それは主要なシャッフルで価格価格、ないわけではありませんします。さらに別の共通の問題は、データサイズがあまりにも異なることが、これは主に、パーティションデータキー値であること(HashPartitionerデフォルトの使用)に起因する実際に均一ではなく、そのようなハッシュアルゴリズムを書き換えるように、改善する必要があります。テストパーティションが)(rdd.partitionsを呼び出すことができます。サイズ()に通知する回数を知りたいです。

Task时间分布。关注Spark UI,在Stage的详情页面上,可以看得到shuffle写的总开销,GC时间,当前方法栈,还有task的时间花费。如果你发现task的时间花费分 布太散,就是说有的花费时间很长,有的很短,这就说明计算分布不均,需要重新审视数据分片、key的hash、task内部的计算逻辑等等,瓶颈出现在耗 时长的task上面。


重用资源。有的资源申请开销巨大,而且往往相当有限,比如建立连接,可以考虑在partition建立的时候就创建好(比如使用mapPartition方法),这样对于每个partition内的每个元素的操作,就只要重用这个连接就好了,不需要重新建立连接。

可供参考的文档:官方调优文档Tuning Spark,Spark配置的官方文档,Spark Programming Guide,JVMGC调优文档,JVM性能调优文档,How-to: Tune Your Apache Spark Jobs part-1 & part-2

注:本文转载自:http://www.raychase.net/3546

おすすめ

転載: blog.csdn.net/weixin_42177380/article/details/90711750