スパークアプリケーションがスパーククラスタランニングに火花提出によって提出され、その後、最終的に火花が提出クラスタが11 Xiangjie下に実行するようにスケジュールされているか何を、提出しました。
0ジョブを送信する火花提出
0.1起動スクリプトの解析
最終的なスクリプトのソースコードを火花提出の分析は、クラスを起動するスクリプトはorg.apache.spark.launcher.Mainある火花送信モード,. /ビン/スパーククラスのジャバスクリプト./bin/spark-classクラスを実行するためのコマンドを示しこのクラスは、SparkSubmitCommandBuilder.javaクラスでスタートパッケージorg.apache.spark.deploy.SparkSubmit.scalaを呼び出すことになります。
/ ** *主なゲートウェイの立ち上げは、ファイルアプリケーションをスパーク。メインアプリケーションのエントリ開始スパーク * *このプログラムは、関連するスパークスパークでCLASSPATHを依存関係を設定する処理し、依存処理パスの設定に関連するクラスを提供し 、別のクラスタ上の層*管理者は、スパークがサポートするモードを展開し。抽象化層は、差のカプセル化トランクモード、スパークをサポートさまざまな展開モードを提供する * / オブジェクトSparkSubmit {
タスク0.2解析 - メインクラスを実行するタスクを送信するように設定
クラスタモデルに応じて、タスクが異なるノード上で解決されます。
タスクの主なタイプが直接ノードを提出ランを提供した。クライアントモード(ローカルモード)。
B。クラスタモード、今回なり、タスクの主なタイプは、クラスタ割当スケジュールのクラスタによって提供されるノード上で実行されています。(特定の割り当てスキップの詳細)
1.待望--SparkContext
/ ** このページのスパーク機能のための*メインエントリポイント。A SparkContextはスパークスパークへの接続でSparkContextで表しクラスタへの正面玄関で、クラスタは、接続を確立する責任がある クラスタ*、および作成ON変数ことRDDS、アキュムレータ、放送に使用することができますクラスタと同時にはRDD、アキュムレータと放送変数を作成することができます。 * *アクティブオンリーワンSparkContextでは、JVMごとにすることができる。 `自分で(停止する必要があります)Spark`アクティブSparkContextそれぞれが唯一のJVM SparkContextの例を実行する前に。 *制限に作成この新しい新しい一つは、最終的に除去することができる; ... SPARK-2243のための詳細を参照してください * *スパークconfigファイルのアプリケーションいずれかで記述構成設定でConfigオブジェクトを@param。 *オーバーライドは、デフォルトの設定は、だけでなく、システムのプロパティ]このコンフィグ。 * / クラスSparkContext(設定:SparkConf)ログ延び{
スパークでは、通信、リソースのアプリケーション、タスク割り当て、クラスタの監視を担当SparkContext。例では、タスクのライフサイクル全体に存在SparkContextスパークドライバプログラム(スパークアプリケーション)に対応するものとして理解することができます。
スパークアプリケーション開発は、最初SparkContextオブジェクトを取得する必要があり、SparkSessionとStreamingContextフロントはSparkContextオブジェクトのインスタンスを作成します。
デフgetOrCreate():SparkSession =同期{ ... ヴァルsparkContext = userSuppliedContext.getOrElse { //設定したアプリ名を指定しない場合 のval randomAppName = java.util.UUID.randomUUID()のtoString。 ヴァルsparkConf =新しいSparkConf() のオプション。 foreachの{場合(K、V)=> sparkConf.set(K、V)} (!sparkConf.contains( "spark.app.name"))であれば{ sparkConf.setAppName(randomAppName) } ヴァルSC = SparkContext.getOrCreate( sparkConf)
プライベート[ストリーミング]ヴァル・SC:SparkContext = { (もし!_sc = NULL){ _sc }それ以外の場合(isCheckpointPresent){ SparkContext.getOrCreate(_cp.createSparkConf()) }他{ SparkContextなしStreamingContextを作成することはできません」(新SparkExceptionを投げます「) } }
DAGScheduler、TaskScheduler、SchedulerBackend、MapOutputTaskMaster、4つのコア対象において後で詳細に説明:SparkContextは、4つのコアオブジェクトが含まれています。
SchedulerBackendは、操作方法に応じて、異なるオブジェクトの例traintあります。StandaloneSchedulerBackendに、例えば、三つの主要な機能があります。
マスター、現在の登録手続きRegisterWithMasterとの通信を担当する1。
2. Excutorは、現在のアプリケーションの配布と管理エグゼキューを登録し、クラスタコンピューティングリソースを受け取ります。
特定のタスクエグゼキュータの実行への送信を担当する3。
インスタンス化1.1の間にSparkContext
インスタンス化する場合1. SparkContextは、プロセスのすべてのメンバーがインスタンス化されるわけではありません。createTaskScheduler SparkContextは場合インスタンス化コードのブロックが実行される配置します。
2. createTaskSchedulerは、例えば、リターン(StandaloneSchedulerBackend、TaskSchedulerImpl)をスタンドアロンに、クラスタの種類に応じて、対応するタプル(SchedulerBackend、TaskScheduler)を返します。
//作成して開始し、スケジューラ のval(schedの、TS)= SparkContext.createTaskScheduler(これ、マスター、deployMode) _schedulerBackend = SCHED _taskScheduler = TS _dagScheduler =新しいDAGScheduler(この) _heartbeatReceiver.ask [ブール](TaskSchedulerIsSet)は TaskSchedulerを開始// taskSchedulerがDAGSchedulerの中DAGScheduler参照を設定した後 、//コンストラクタ _taskScheduler.start()
3.ファイル名を指定して実行_taskScheduler.start()メソッド、メソッド呼び出しを開始SchedulerBackend(ここではStandaloneSchedulerBackend)。
4.タスク開始方法は、パッケージ情報、通話StandaloneAppClientをStandaloneSchedulerBackendメソッドを起動する(ここでの唯一のジョブ情報を登録し、ジョブをサブミットしません)。
//スケジューラに登録するために、いくつかの必要なコンフィグと執行を開始 ヴァルsparkJavaOpts = Utils.sparkJavaOpts(confに、SparkConf.isExecutorStartupConf) ヴァルjavaOpts = sparkJavaOpts ++ extraJavaOpts ヴァルコマンド=コマンド(「org.apache.spark.executor.CoarseGrainedExecutorBackend」 、 引数、sc.executorEnvs、classPathEntries ++ testingClassPath、libraryPathEntries、javaOpts) ヴァルappUIAddress = sc.ui.map(_。appUIAddress).getOrElse( "") のVal coresPerExecutor = conf.getOption( "spark.executor.cores") .MAP(_。オーバーライド:) ... クライアント=新しいStandaloneAppClient(sc.env.rpcEnv、マスター、appDesc、この、CONF) client.start()
5. StandaloneAppClient(クライアントのマスタータスクに登録され、いないドライバー)メソッドは、そのONSTARTメソッドを呼び出し、ClientEndPointオブジェクトを作成し、ONSTARTがマスターに登録するregisterWithMasterメソッドを呼び出します。
2.マスタータスク登録情報
登録情報StandaloneAppClientの受信方法マスターを受け、主に以下のタスクを完了するために:
1.登録アプリケーション情報アプリ
2.成功した登録情報driver.send(RegisteredApplication(app.id、自己) ) 要求元のクライアント登録StandaloneAppClient(へのこの時間は、タスクを登録されています)
3.タスクのためのリソースを割り当てるためにスケジュールメソッドを呼び出し
ケースRegisterApplication(説明、ドライバ)=> // TODO防止は、いくつかのドライバから登録を繰り返す (状態== RecoveryState.STANDBY)場合{ //応答を送信しない、無視 }他{ LOGINFO( "登録アプリ" + description.name ) ヴァルアプリ= createApplication(説明、ドライバ) registerApplication(APP) LOGINFO( "登録アプリ" + description.name + "IDと" + app.id) persistenceEngine.addApplication(APP) driver.send(RegisteredApplication(app.id、自己)) スケジュール() }
作業者は、タスクにリソースを割り当て、対応Dirverエグゼキュータを起動し、タスクを実行し、リソース割り当てスケジュールメインドライバとワーカーのための方法、および特定Dirverエグゼキュータは、ワーカーを実行します。
/ ** *アプリケーションを待っている間に、現在利用可能なリソースをスケジュールします。このメソッドが呼び出されます *すべての新しいアプリが参加する時間やリソースの可用性の変更を。 * / プライベートデフスケジュール():単位= { (!状態= RecoveryState.ALIVE){場合 のリターンは } //ドライバの執行を厳密に優先されます 。valのshuffledAliveWorkers = Random.shuffle(workers.toSeq.filter(_状態== WorkerState .ALIVE)) ヴァルnumWorkersAlive = shuffledAliveWorkers.size VAR curPos = 0 のために(ドライバ< - waitingDrivers.toList){// waitingDriversのコピーを反復 //我々は、ラウンドロビン方式で各待機運転者に労働者を割り当てます。各ドライバについては、我々 ドライバを割り当てられた最後の作業員からスタートし、我々が持っているまで、以降継続// //すべての生きている労働者を調査しました。 VAR打ち上げ= falseの VAR numWorkersVisited = 0 しばらく(numWorkersVisited <numWorkersAlive &&!発売){ valの作業員= shuffledAliveWorkers(curPos) numWorkersVisited + = 1 の場合(worker.memoryFree> = driver.desc.mem && worker.coresFree> = driver.desc .cores){ launchDriver(労働者、運転手)//加载ドライバ waitingDrivers - =ドライバが 起動= TRUE } curPos =(curPos + 1)%numWorkersAlive } } startExecutorsOnWorkers ()労働者を開始// }
3. 労働者のスタートドライバー
3.1ドライバの起動
マスターLaunchDriverは、完全な起動を作成し、オブジェクトの後にオブジェクトのstartメソッドを呼び出すためのメッセージが労働者、労働者がメッセージを受信した後DriverRunnerを作成することです送信します。
ケースLaunchDriver(driverId、するDriverDesc)=> LOGINFO( "ドライバーの$ driverIdを起動するために尋ねられ、" S) ヴァルドライバ=新しいDriverRunner
最後に、この方法は、ドライバrunDriverによってプロセスを開始prepareAndRunDriverを呼び出します開始。
ユーザーのローカルへのjarパッケージdownloadUserJar方法。
prepareAndRunDriver DEFプライベート[ワーカー]()のInt = { ヴァルdriverDir = createWorkingDirectory() ヴァルlocalJarFilename = downloadUserJar(driverDir) DEF substituteVariables(引数:文字列):文字列=引数一致{ 場合"{{WORKER_URL}}" => workerUrl ケース"{{USER_JAR}}" => localJarFilename 場合その他=>その他 } // TODO:私たちは、複数のjarファイルを提出する機能を追加した場合、彼らはまた、ここで追加する必要があり ヴァルビルダー= CommandUtils.buildProcessBuilder(driverDesc.command、SecurityManagerを、 driverDesc.mem 、sparkHome.getAbsolutePath、substituteVariables) runDriver(ビルダー、driverDir、driverDesc.supervise) }
3.2ドライバのいくつかの問題点
A。ドライバーはDriverDescriptionに次のように提出されたアプリケーションは、定義されていることを意味します。
DEFのtoStringをオーバーライドする:文字列= S "DriverDescription($ {command.mainClass})"
B。ドライバーは、労働者実行でロードマスター、worker.endpoint.send(LaunchDriver(driver.id、driver.desc))によって割り当てられた特定の労働者、上で実行されます。
{launchDriver(:WorkerInfo、ドライバDriverInfoワーカー)デフプライベート LOGINFO( "起動運転" + driver.id + + worker.id "労働者に") worker.addDriver(ドライバ) driver.worker =一部(作業者) worker.endpoint .send(LaunchDriver(driver.id、driver.desc)) driver.state = DriverState.RUNNING }
アプリケーションC。ドライバーが提出されていない、労働者のドライバーがDriverRunnerオブジェクトをインスタンス化され、スタンドアローンでのプロセスの労働者は、ドライバの実行と再起動に失敗を管理する責任があります。
/ ** *自動的に失敗した場合に、ドライバを再起動するなど、1つのドライバの実行を、管理します。 *これは、現在、スタンドアロンクラスタデプロイモードで使用されています。 * / プライベート(クラスDriverRunner [展開]を
D。登録およびスケジュール塗布法、ドライバに対応するアプリケーションの間にマスターから見た、労働者(エグゼキュータ)が複数存在してもよいです。
4.ワーカー開始キュータ
startExecutorsOnWorkersメソッド呼び出しのマスタースケジュールは最終的に実行するタスクをインスタンス化するために、ヴァル・マネージャー=新しいExecutorRunner ExecutorRunnerオブジェクトによって、LaunchExecutor労働者にメッセージを送信します。
ExecutorRunner方法はfetchAndRunExecutorがタスクを実行するための新しいプロセスを作成して呼び出します。
/ ** *ダウンロードして私たちのApplicationDescriptionで説明キュータ実行 * / プライベートデフfetchAndRunExecutorを(){ {試みる プロセスの起動// ヴァル・ビルダー= CommandUtils.buildProcessBuilder(appDesc.command、新しいSecurityManagerのファイル(conf)を、
** appDesc.commandワーカーノードがExecutorRunnerを開始する、すなわち、ExecutorRunnerプロセスはCoarseGrainedExecutorBackendを開始する、入ってくるコマンドをStandaloneSchedulerBackendします
ヴァル・コマンド=コマンド( "org.apache.spark.executor.CoarseGrainedExecutorBackend"、
ONSTART CoarseGrainedExecutorBackend方法では、登録要求をRedisterExecutorドライバに送信されます。
オーバーライドONSTARTデフ(){ LOGINFO( "ドライバへの接続:" + driverUrl) rpcEnv.asyncSetupEndpointRefByURI(driverUrl).flatMap {refは=> //これは非常に高速な動作であるので、私たちは"ThreadUtils.sameThread"を使用することができます (=いくつかのドライバをREF) ref.ask [ブール](RegisterExecutor(executorId、自己、ホスト名、コア、extractLogUrls))
登録要求ドライバーがCoarseGrainedExecutorBackend登録に結果を返します処理した後、登録が成功したCoarseGrainedExecutorBackendは、これまでの執行が作成した、新しいエグゼキュータを作成しています。
部分写像[でも、単位] = {:受信DEFオーバーライドする 場合RegisteredExecutor => LOGINFO( "正常ドライバに登録") {試みる executorが=新しいエグゼキュータ(executorId、ホスト名、ENV、userClassPath、のisLocal =偽) }キャッチ{ 場合致命的ではないが( E)=> exitExecutor(1)+ e.getMessage、E "起因するexecutorを作成できません" }
*あなたが複数のエグゼキューに各ワーカーを開始することができ、各エグゼキュータは、独立したプロセスです。
*フロー・チャートは、以下の利用者は、スパークのタスクを提出示し