web-dev-qa-db-ja.com

Spark:プログラムでクラスターコアの数を取得する

私はsparkアプリケーションをヤーンクラスターで実行します。私のコードでは、データセットにパーティションを作成するためにキューの利用可能なコアの数を使用しています。

Dataset ds = ...
ds.coalesce(config.getNumberOfCores());

私の質問:構成ではなくプログラムでキューの利用可能なコア数を取得するにはどうすればよいですか?

9
Rougher

クラスター内のエグゼキューターの数とコアの数の両方をSparkから取得する方法があります。 Scala過去に使用したユーティリティコードの一部です。Javaに簡単に適応できるはずです。2つの重要なアイデアがあります。

  1. ワーカーの数は、エグゼキューターの数から1を引いた数またはsc.getExecutorStorageStatus.length - 1です。

  2. ワーカーごとのコアの数は、ワーカーでJava.lang.Runtime.getRuntime.availableProcessorsを実行することで取得できます。

コードの残りの部分は、Scala implicitsを使用してSparkContextに便利なメソッドを追加するためのボイラープレートです。1.x年前にコードを書いたため、SparkSessionを使用していません。

最後のポイントの1つは、データが偏っている場合にパフォーマンスを向上させることができるため、複数のコアに合体させることをお勧めすることがよくあります。実際には、データのサイズと、ジョブが共有クラスターで実行されているかどうかに応じて、1.5倍から4倍の範囲で使用します。

import org.Apache.spark.SparkContext

import scala.language.implicitConversions


class RichSparkContext(val sc: SparkContext) {

  def executorCount: Int =
    sc.getExecutorStorageStatus.length - 1 // one is the driver

  def coresPerExecutor: Int =
    RichSparkContext.coresPerExecutor(sc)

  def coreCount: Int =
    executorCount * coresPerExecutor

  def coreCount(coresPerExecutor: Int): Int =
    executorCount * coresPerExecutor

}


object RichSparkContext {

  trait Enrichment {
    implicit def enrichMetadata(sc: SparkContext): RichSparkContext =
      new RichSparkContext(sc)
  }

  object implicits extends Enrichment

  private var _coresPerExecutor: Int = 0

  def coresPerExecutor(sc: SparkContext): Int =
    synchronized {
      if (_coresPerExecutor == 0)
        sc.range(0, 1).map(_ => Java.lang.Runtime.getRuntime.availableProcessors).collect.head
      else _coresPerExecutor
    }

}

更新

最近、getExecutorStorageStatusが削除されました。 SparkEnvblockManager.master.getStorageStatus.length - 1を使用するように切り替えました(マイナス1はドライバー用です)。 envSparkContextを介してこれにアクセスする通常の方法は、org.Apache.sparkパッケージの外部からはアクセスできません。したがって、カプセル化違反パターンを使用します。

package org.Apache.spark

object EncapsulationViolator {
  def sparkEnv(sc: SparkContext): SparkEnv = sc.env
}
15
Sim

ほぼ同じ質問の答えを探しているときにこれを見つけました。

見つけた:

Dataset ds = ...
ds.coalesce(sc.defaultParallelism());

oPが求めていたものを正確に実行します。

たとえば、5ノードx 8コアクラスターは、defaultParallelismに対して40を返します。

0
Steve C

Databricks によると、ドライバとエグゼキュータが同じノードタイプである場合、これが方法です。

Java.lang.Runtime.getRuntime.availableProcessors * (sc.statusTracker.getExecutorInfos.length -1)
0
zaxme

すべてのマシンでジョブを実行してコアの数を尋ねることもできますが、Sparkで利用できるものとは限りません(@tribbloidが別の回答のコメントで指摘しているように):

import spark.implicits._
import scala.collection.JavaConverters._
import sys.process._
val procs = (1 to 1000).toDF.map(_ => "hostname".!!.trim -> Java.lang.Runtime.getRuntime.availableProcessors).collectAsList().asScala.toMap
val nCpus = procs.values.sum

シェルで(2つのワーカーを持つ小さなテストクラスターで)実行すると、次のようになります。

scala> :paste
// Entering paste mode (ctrl-D to finish)

    import spark.implicits._
    import scala.collection.JavaConverters._
    import sys.process._
    val procs = (1 to 1000).toDF.map(_ => "hostname".!!.trim -> Java.lang.Runtime.getRuntime.availableProcessors).collectAsList().asScala.toMap
    val nCpus = procs.values.sum

// Exiting paste mode, now interpreting.

import spark.implicits._                                                        
import scala.collection.JavaConverters._
import sys.process._
procs: scala.collection.immutable.Map[String,Int] = Map(ip-172-31-76-201.ec2.internal -> 2, ip-172-31-74-242.ec2.internal -> 2)
nCpus: Int = 4

通常、クラスターにlots台のマシンがある場合は、範囲にゼロを追加します。 2台のマシンのクラスターでも、10000は数秒で完了します。

これはおそらく、(@ SteveCの回答のように)sc.defaultParallelism()が提供するよりも多くの情報が必要な場合にのみ役立ちます。

0
James Moore