繁体   English   中英

使用太多资源进行火花作业

[英]Spark job using too many resources

我正在对50个容器的纱线簇进行交叉验证研究。 数据约600,000行。

该作业在大多数情况下都能正常运行,但是会在群集(启动作业的计算机)的驱动程序服务器上使用大量RAM和CPU资源:4个CPU内核中的3个。 但是,我不能使用那么多资源,因为该服务器由几个人使用。

我的问题是:

  1. 为什么我的代码在驱动程序上使用了如此多的资源?
  2. 我如何修改它,使其消耗更少的驱动程序资源,而在群集节点上消耗更多资源?

我不知道有多少火花,但是我对第一个问题的押注是,我应该使用比数组和ParArrays更多的RDDS,但是我不知道怎么做...

这是我的代码:

val sc: SparkContext = new SparkContext()
  .setMaster( "yarn-client" )
  .set("spark.serializer", "org.apache.spark.serializer.KryoSerializer")
  .set("spark.kryo.registrator", "com.amadeus.ssp.tools.SSPKryoRegistrator")

val data = sc.textFile("...").map(some pre-treatment...)

// Parameters 
  val numModels = Array(5)
  val trainingRatioMajMin = 0.7
  // Tree Ensemble
  val numTrees = Array(50)
  val maxDepth = Array(30)
  val maxBins = Array(100)
  // RF
  val featureSubsetStrategy = Array("sqrt")
  val subsamplingRate = Array(1.0)

// Class for model
class Model(model: Array[RandomForestModel]) {
  def predict(data:RDD[Vector]) : RDD[Double] = {
    data.map(p => predict(p))
  }
  def predictWithLabels(data:RDD[LabeledPoint]) : RDD[(Double, Double)] = {
    data.map(p => (p.label, predict(p.features)))
  }
  def predict(point:Vector): Double = {
    model.map(m => m.predict(point)).sum / model.length
  }
}

 val CV_params: Array[Array[Any]] = {
    for (a <- numTrees; b <- maxDepth; c <- maxBins; d <- featureSubsetStrategy;
        e <- subsamplingRate; f <- numModels) yield Array(a, b, c, d, e, f)
  }

 // Sampling dataset 
 def sampling(dataset:RDD[LabeledPoint], fraction :Double): (Array[RDD[LabeledPoint]], RDD[LabeledPoint]) = {
    logInfo("Begin Sampling")
    val dataset_maj = dataset filter(_.label == 0.0)
    val dataset_min = dataset filter(_.label == 1.0)
    dataset_maj.persist(org.apache.spark.storage.StorageLevel.MEMORY_ONLY_SER)

    val data =  ((1 to params(5).asInstanceOf[String]).map { sample =>
      dataset_maj.sample(false, fraction)
    }.toArray, dataset_min)
    dataset_maj.unpersist()
    logInfo("End Sampling")
    data
  }

// Train the model
  def classificationModel(params:Array[Any], training:RDD[LabeledPoint]) : EasyEnsemble_Classifier_Model = {
    val (samples, data_min) = sampling(data, fraction)
    data_min.persist(org.apache.spark.storage.StorageLevel.MEMORY_ONLY)
    val models = samples.par.map { sample =>
      val strategy = new Strategy(Algo.Classification, org.apache.spark.mllib.tree.impurity.Gini, params(1).asInstanceOf[Int],
      numClasses, params(2).asInstanceOf[Int],  QuantileStrategy.Sort, categoricalFeaturesInfo, 1, 0.0, 256, params(4).asInstanceOf[Double], false, 10)
      val model = RandomForest.trainClassifier(sample ++ data_min, strategy, params(0).asInstanceOf[Int], params(3).asInstanceOf[String], 0)
      logInfo(s"RF - totalNumNodes: ${model.totalNumNodes} - numTrees: ${model.numTrees}")
      model
    }.toArray
    data_min.unpersist()
    logInfo(s"RF: End RF training\n")
    new Model(models)
  }


 ///// Cross-validation
val cv_data:Array[(RDD[LabeledPoint], RDD[LabeledPoint])] = MLUtils.kFold(data, numFolds, 0)

logInfo("Begin cross-validation")
val result : Array[(Double, Double)] = cv_data.par.map{case (training, validation) =>
  training.persist(org.apache.spark.storage.StorageLevel.MEMORY_ONLY)
  validation.persist(org.apache.spark.storage.StorageLevel.MEMORY_ONLY)

  val res :ParArray[(Double, Double)] = CV_params.par.zipWithIndex.map { case (p,i) =>
    // Training classifier
    val model = classificationModel(p, training)
    // Prediction
    val labelAndPreds = model.predictWithLabels(validation)
    // Metrics computation
    val bcm = new BinaryClassificationMetrics(labelAndPreds)
    logInfo("ROC: %s".format(bcm.roc().collect().map(_.toString).reduce(_ + " - " + _)))
    logInfo("PR: %s".format(bcm.pr().collect().map(_.toString).reduce(_ + " - " + _)))
    logInfo("auPR: %s".format(bcm.areaUnderPR().toString))
    logInfo("fMeasure: %s".format(bcm.fMeasureByThreshold().collect().map(_.toString).reduce(_ + " - " + _)))
    (bcm.areaUnderROC() / numFolds, bcm.areaUnderPR() / numFolds)
  }

  training.unpersist()
  validation.unpersist()
  res
}.reduce((s1,s2) => s1.zip(s2).map(t => (t._1._1 + t._2._1, t._1._2 + t._2._2))).toArray

val cv_roc = result.map(_._1)
val cv_pr = result.map(_._2)

logInfo("areaUnderROC: %s".format(cv_roc.map(_.toString).reduce( _ + " - " + _)))
logInfo("areaUnderPR: %s".format(cv_pr.map(_.toString).reduce( _ + " - " + _)))

// Extract best params
val which_max = (metric match {
  case "ROC" => cv_roc
  case "PR" => cv_pr
  case _ =>
    logWarning("Metrics set to default one: PR")
    cv_pr
}).zipWithIndex.maxBy(_._1)._2

best_values_array = CV_params(which_max)
CV_areaUnderROC = cv_roc
CV_areaUnderPR = cv_pr

编辑

我用它启动

spark-submit \
    --properties-file spark.properties \
    --class theClass \
    --master yarn-client \
    --num-executors 50 \
    job.jar 

spark.properties

spark.rdd.compress               true
spark.executor.extraJavaOptions  -XX:+PrintGCDetails -Djava.library.path=/opt/cloudera/parcels/CDH/lib/hadoop/lib/native
org.apache.spark.io.SnappyCompressionCodec

spark.yarn.maxAppAttempts   1
yarn.log-aggregation-enable true

spark.executor.memory              5g
spark.yarn.executor.memoryOverhead 1024

spark.cassandra.connection.host            172.16.110.94
spark.cassandra.connection.timeout_ms      60000
spark.cassandra.connection.compression     SNAPPY

运行作业时,可以限制作业可以在驱动程序上访问的可用内核和内存:

$ spark-submit \
    --class foo.bar.Main \
    --conf spark.driver.memory=1g \
    --conf spark.driver.cores=1 \
    --conf spark.executor.memory=10g \
    --conf spark.executor.cores=6
    /path/to/job.jar <options>

使用Yarn运行时,您还可以更改可用执行程序的数量。

其余内容请参见“ Spark配置选项”文档。

[编辑]

我刚刚注意到,在您使用Spark的代码中,我看不到任何地方。 我没有看到任何Spark上下文,也没有在集合(数组)上调用并行化的任何地方。 如果不这样做,它们将不会并行分发和处理。 我本人对Spark还是很陌生,但是除非您只是其中的一小部分,否则我看不到您的代码如何使用Spark。

我将告诉您为什么要使用collect() API吃Driver资源。

根据Apache 文档

collect()在驱动程序中将数据集的所有元素作为数组返回。 这通常在返回足够小的数据子集的过滤器或其他操作之后很有用。

如果您有N个分区(在您的情况下为50个容器),则来自所有分区的数据将在驱动程序处收集。

如果您有大量数据, collect()可能会OutOfMemory驱动程序出现OutOfMemory错误。

看一下有关如何处理这种情况的一些有用的问题:

Spark:从RDD到本地计算机检索大数据的最佳实践

来自Cloudera博客的Spark应用程序微调

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM