オリジナルます。http://litaotao.github.io/boost-spark-application-performance
このシリーズは、からいくつかのアイデアをスパークスパーク+参考記事+個人練習のプロセスのいくつかの理解の学習過程で自分の記録の包括的な理解です。ちょうどそう記録されませんし、文書のオリジナルの英語テキストが時々表示され、すべての主要な、不必要な詳細を理解することができるように、火花を記録し、個人の研究ノートを整理するために、このようなシリーズを書いて、それは、理解のない影響を与えません。翻訳されました。最高のリード参照記事や公式文書の詳細については。
第二に、このシリーズは、最新のスパーク1.6.0シリーズが始まったに基づいて、すぐに最新の更新をスパーク、レコードのどのバージョンが良いかが必要です。
最後に、あなたは内容が間違っていると感じた場合、メッセージノートを歓迎し、24時間以内のすべてのメッセージは、どうもありがとうございました、返信しなければなりません。
ヒント:イラストは明らかに思われる場合、あなたがすることができます:1ズームページ; 2は、元のああを表示する新しいタブ画像を開きます...
1.优化?どうして?どうやって?いつ?何?
「スパークアプリケーションも最適化される必要がありますか?」、多くの人々がこの疑問を持っていることがあり、「すでにコードジェネレータ、オプティマイザの実行、パイプラインまたはそれの何かを持っていません?。」はい、火花が速く実行時に、あなたのコードを作成する組み込みツールのいくつかの強力な列を持っています。しかし、すべてのツールに依存している場合、フレームワークを行うには、私はそれが2つのだけ問題を示し思う:1あなただけの理由を知っているこれらのこのフレームワークを知って、そしてない;あなたが唯一の写真2枚あるようです。あなたは、あなた、他の人が簡単にアプリケーションのように火花を書くことができなかったので、あなたが交換可能で、塗装ひょうたんひしゃく;
、最適化のスパーク・アプリケーションを実行するには、次のいくつかのポイントから起動する場合には十分です。
- なぜ:あなたは、リソースが限られているので、本番アプリケーション環境ので不安定性、優れた最適化とテストの多くの要因があるだろう、生産前に不安定性の影響を軽減するための唯一の方法です。
- どのように実行します。Web UIの+ログは天剣とTulongダオを行うために最適化されて、その上でこれらの2点を把握することができます。
- ときにそれを行うには:成熟したアプリケーションの開発には、ビジネス要件が満たされたとき、あなたはニーズやスケジュールに応じて行うことを始めることができます。
- 何をすべきか:メモリ、ディスクIO、ネットワークIO:一般的に、火花を最適化されたアプリケーションの80%は、三つの領域に集中しています。その後構築するように設定されている細かい点、クラスタおよびファイルシステムドライバ、メモリの執行、シャッフルの設定、ファイルシステムの構成、クラスタは、[例えばより高速なネットワーク、ローカル・エリア・ネットワーク内のファイルシステムとクラスタをしようと、あなたができる場合可能にするドライバと、クラスタ内のローカルエリアネットワーク、時々ドライバに作業者からデータを返す必要があるため]
- 注:自分自身の理由のタイムプログラムのほとんどが、あなたは手順のチェックを開始する前には、すべてのワーカーマシンの状況がああ、正常であることを確認するのが最善ですが、すべてが、プログラム自体から始める最適化に取り付かないでください。たとえば、マシンの負荷、ネットワークの状態。
databricksから下の写真はのシェア チューニングデバッグApacheとスパーク 非常に興味深いが、それは非常に右置くために、ああ、ハハ。
OK、のは、いくつかの一般的な最適化の方法を見てみましょう。
2.配分と合体
-
Spark provides the `repartition()` function, which shuffles the data
-
across the network to create a new set of partitions. Keep in mind
-
that repartitioning your data is a fairly expensive operation. Spark
-
also has an optimized version of `repartition()` called `coalesce()`
-
that allows avoiding data movement, but only if you are decreasing
-
the number of RDD partitions. To know whether you can safely call
-
coalesce(), you can check the size of the RDD using `rdd.partitions.size()`
-
in Java/Scala and `rdd.getNumPartitions()` in Python and make sure
-
that you are coalescing it to fewer partitions than it currently has.
-
概要:あなたは再RDD断片化したい、目標数は、使用エリアエリアの現在の数未満である場合にはcoalesce
、使用しないでください repartition
。 partition
参照して、最適化の詳細は、学習スパークの章4
スパーク3.渡す機能
Pythonでは、私たちは、Sparkに関数を渡すための3つのオプションがあります。
- ラムダ式
word = rdd.filter(lambda s: "error" in s)
- トップレベルの関数
-
import my_personal_lib
-
-
word = rdd.filter(my_personal_lib.containsError)
- ローカルに定義された関数
-
def containsError(s):
-
return "error" in s
-
word = rdd.filter(containsError)
関数を渡すときに注意する1つの問題は、不注意機能を含むオブジェクトをシリアル化されます。あなたがオブジェクトのメンバーである、またはオブジェクト(例えば、self.field)内のフィールドへの参照が含まれている機能を渡すと、スパークはあなたが必要とする情報のビットよりもはるかに大きくなることがワーカーノードにオブジェクト全体を送信します。時には、これはまた、あなたのクラスはPythonがpickle化する方法を見つけ出すことができないオブジェクトが含まれている場合は、あなたのプログラムは、失敗する可能性があります。
-
### wrong way
-
-
class SearchFunctions(object):
-
def __init__(self, query):
-
self.query = query
-
def isMatch(self, s):
-
return self.query in s
-
def getMatchesFunctionReference(self, rdd):
-
# Problem: references all of "self" in "self.isMatch"
-
return rdd.filter(self.isMatch)
-
def getMatchesMemberReference(self, rdd):
-
# Problem: references all of "self" in "self.query"
-
return rdd.filter(lambda x: self.query in x)
-
-
### the right way
-
-
class WordFunctions(object):
-
...
-
def getMatchesNoReference(self, rdd):
-
# Safe: extract only the field we need into a local variable
-
query = self.query
-
return rdd.filter(lambda x: query in x)
4.ワーカーリソースの割り当て:CPU、memroy、執行
比較的深い話題が、異なる展開モデルでは、同じ[スタンドアロン、糸、mesos]ではありませんここに何かアドバイスを与えることはできません。唯一の目的は、考慮に入れ機械自体のプロセスの一部を取って、使用するスパークに独立しているすべてのリソースを償還考慮していない、プロセスのスパーク依存ネットワーク、IO集約型、計算集約タスクの状況[、いくつかの長期ライブタスク]などが挙げられます。
それは、実際の例に発行されたリソースのチューニングの後に私のところに来たとき、ここでは唯一の、いくつかのビデオ、スライドやブログ、特定の条件をお勧めすることができます。
前記シャッフルブロックサイズの制限
スパークシャッフルブロックは、最後の2ギガバイト以内NO大きくすることができる ブロックサイズでスパークshuffleは超えることはできません- 2グラムを 。
スパークコール使っ たByteBufferの データ・キャッシュ・シャッフルようなデータ構造を、これのByteBufferの データは2グラムシャッフル時間以上になると、shuflleプロセスが間違って行きますので、メモリのデフォルトの割り当ては2グラムです。データのサイズに影響を与える要因はいくつかの一般的なありシャッフル:
- パーティションの数、より多くのパーティションは、より少ないデータが各パーティションに分配され、より容易に大きすぎるシャッフルデータにつながります。
- データの不均一な分布は、典型的に groupByKey 、いくつかの重要なデータの存在は、データ・パーティション上に位置するキーで、その結果、大きすぎる備える多すぎる、それは遅くshuflleが2グラムよりも大きいブロックトリガすることが可能です。
このようなパーティションの数の一般的な増加、解決する方法があります するアプリケーションの記述がスパークするとトップ5の間違い 、ここで述べたが、各パーティション上のデータを作ることが期待できるだけの原則について話をするだけ参考のために、128メガバイト程度である、または、ここで特定のシーン特定の分析を必要としますはっきり行に、完璧な仕様はありません。
- ときより大きなパーティション番号を指定しsc.textfile
- spark.sql.shuffle.partitions
- rdd.repartition
- rdd.coalesce
TIPS
:
2000未満とパーティション2000は2つのシナリオよりも大きい場合には、時刻シャッフルに情報を記録するために使用されるスパーク異なるデータ構造は、パーティション2000よりも大きい、情報を格納するためのより効率的な代替[圧縮]のデータ構造が存在することになります。あなたのパーティションが2000にはありませんが、2000年は非常に近いのであれば、あなたはパーティションが2000以上に設定されているので安心できます。
-
def apply(loc: BlockManagerId, uncompressedSizes: Array[Long]): MapStatus = {
-
if (uncompressedSizes.length > 2000) {
-
HighlyCompressedMapStatus(loc, uncompressedSizes)
-
} else {
-
new CompressedMapStatus(loc, uncompressedSizes)
-
}
-
}
パーティション - 並列の6レベル
すべてのタスクが実行段階、いくつかの説明のパフォーマンス指標のいくつかを見てみましょう:
Scheduler Delay
:時間は、それが割り当てられたタスクを刺激するのにかかりますExecutor Computing Time
:エグゼキュータのタスクの実行時間を過ごしましたGetting Result Time
:タスクの実行時間の結果を過ごしゲットResult Serialization Time
:タスクの実行結果のシリアル化の時間Task Deserialization Time
:タスクのデシリアライゼーション時間Shuffle Write Time
:シャッフルデータは、時間を書きますShuffle Read Time
:それはデータを読み込むのにかかる時間をシャッフル
ここでのポイントは、 level of parallel
パーティションの数を指し、実際には、ほとんどの場合、変更のパーティション番号は、上記のいくつかの指標の変化に影響を与えます。私たちのチューニング時間は、非常に多くの場合、上記の指標の変化を参照してください。場合は、次のようにパーティションの変更、いくつかの指標の変化は上記のとおりです。
- [データスキューの問題を導入するのは簡単]は小さすぎるパーティション
Scheduler Delay
:変化なしExecutor Computing Time
:不安定、一部は小さいが、平均的に比較的大きなGetting Result Time
:不安定、一部は小さいが、平均的に比較的大きなResult Serialization Time
:不安定、一部は小さいが、平均的に比較的大きなTask Deserialization Time
:不安定、一部は小さいが、平均的に比較的大きなShuffle Write Time
:不安定、一部は小さいが、平均的に比較的大きなShuffle Read Time
:不安定、一部は小さいが、平均的に比較的大きな
- パーティションが大きすぎます
Scheduler Delay
:変化なしExecutor Computing Time
:比較的小さく、平均で、比較的安定Getting Result Time
:比較的小さく、平均で、比較的安定Result Serialization Time
:比較的小さく、平均で、比較的安定Task Deserialization Time
:比較的小さく、平均で、比較的安定Shuffle Write Time
:比較的小さく、平均で、比較的安定Shuffle Read Time
:比較的小さく、平均で、比較的安定
これは、パーティション、それの数を設定する方法をすべきですか?ここでも、具体的な式と仕様が存在しない、我々は一般的に数回の後に、より最適な結果を持ってしようとしています。しかし、目的は次のとおりです。少し変更間隔の期間内に実行される各タスクのための時間を作るためにしようと、データスキューの問題が発生しないようにしてください。
7.データ・スキュー
ほとんどの時間、私たちは、分散コンピューティング効果の利点は以下の図のようにする必要がありますことを願っています:
しかし、場合によっては、データ・スキューと呼ばれる、この効果を下回っています。そのデータはされていない 大致均匀
ようなタスクのために、タスクの実行時間は、処理されるべき最初のデータブロックの全体的な時間に依存し、クラスターに分配します。多くの分散システムでは、データスキューが大きな問題は、このような分散キャッシュと、キャッシュは、次にときマシン10のマシンが、一台のマシン上に落ちるデータの50%が存在することが想定されていますダウン後のデータのキャッシュ全体オフ一般失うことになる、少なくとものキャッシュヒット率50%[はより確かに大きいです]。分散キャッシュのこれもあり、多くは、一貫性のあるハッシュを導入するために導入される 虚拟节点 vnode
理由。
一貫したハッシュ回路図:
トピックに戻る、データの問題を解決する方法は、火花をスキュー?まず、問題のシーンと発生ルートをクリア:一般的な、すべての(キー、値)のデータ型、キーの偏在では、このシナリオでは、より一般的な方法でキー処理塩を実行することである[塩中国人が知っているべきではありません言う方法]、例えば、そこに二つの重要な(KEY1、KEY2)、及びKEY1、KEY2に対応する大規模なデータセットであり、対応するデータセットが比較的小さいこと、キーは、キーの複数(key1-1、KEY1に拡張することができます-2、...、KEY1-N、 key2-1、key2-2、...、KEY2-M)、 およびことを確実にする key1-*
、対応する元のデータである key1
対応に設定されたデータには、付属の key2-*
対応するデータがオリジナルであります key2
セットからの対応するデータを分割します。この後、我々は m+n
キーを、データセットに各キーに相当するが、増加並列比較的小さく、各並列処理プログラムのデータサイズが少し差を設定し、効率的な並列処理を大幅に高速化することができます。これら2では、私は、このアプローチでは、すべての株式を言及しています:
8.デカルト操作を避けます
rdd.cartesian 操作はデカルト大きさは、成長のレベルの二乗ではなく、時間がかかるだけではなく、大規模なデータセットは、スペースを消費する場合は特に、非常に時間がかかります。
-
>>> rdd = sc.parallelize([1, 2])
-
>>> sorted(rdd.cartesian(rdd).collect())
-
[(1, 1), (1, 2), (2, 1), (2, 2)]
9.回避シャッフル可能な場合
デフォルトのシャッフルスパークは、書き込みデータディスクの段階にあり、その後、次の段階、その後、ディスクから読み取ります。ここでは、ディスクIOのパフォーマンスに大きな影響、データの特に大容量。
10.使用reduceByKeyの代わりGroupByKey可能な場合
11.使用treeReduceの代わりに、可能な場合減らします
12.使用Kryoシリアライザ
RDDのためにシャッフル及びキャッシュは、データがシリアル化されるスパーク・アプリケーションは、データは、ボトルネックのシリアル化アプリケーションであってもよく、この時のIOに加えて、格納することができます。高効率を確保することができ、データのシリアル化のシリアル化の時にkryo配列データベースを使用することをお勧めします。
sc_conf = SparkConf()
sc_conf.set("spark.serializer", "org.apache.spark.serializer.KryoSeria