此Spark / Scala代码的性能瓶颈在哪里?

时间:2015-01-03 23:53:30

标签: scala apache-spark

首先让我指出我对Spark和Scala都很陌生。我试图通过尝试迁移我过去做过的Hadoop Map / Reduce Jobs之一来试图调查承诺的Spark性能。这项工作需要花费14分钟在Hadoop上使用3x r3.2xlarge机器输入16个压缩的bzip文件,每个文件170mb。我将它最好的翻译成Scala / Spark,就像这样:

val conceptData = spark.textFile(inputPath)
val result = conceptData.repartition(60).cache()
    .map(line => {val metrics = JsonUtil.fromJson[ArticleMetrics](line); (metrics.source, metrics.data.get("entities").get)})
    .flatMap(metrics => metrics._2.map(t => (t._1,(1,List((metrics._1,t._2.head))))))
    .reduceByKey((a,b) => combine(a,b))
    .map(t => t._1 + "\t" + t._2._1 + "\t" + print(t._2._2))
result.saveAsTextFile(outputPath)

def print(tuples: List[(String, Any)]): String =
{
  tuples.map(l => l._1 + "\u200e" + l._2).reduce(_ + "\u200f" + _)
}

def combine(a: (Int, List[(String, Any)]), b: (Int, List[(String, Any)])): (Int, List[(String, Any)]) =
{
  (a._1 + b._1,a._2 ++ b._2)
}

object JsonUtil {
  val mapper = new ObjectMapper() with ScalaObjectMapper
  mapper.registerModule(DefaultScalaModule)
  mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false)

  def fromJson[T](json: String)(implicit m : Manifest[T]): T = {
    mapper.readValue[T](json)
  }
}

我在开头使用了repartition命令将分区设置为60,因为我读到了每个核心有2-3个分区的好处。 我在相同的3x r3.2xlarge机器上运行这个Spark工作(每个机器有8个内核和58G可用),所以我以下列方式提交我的工作:

spark/bin/spark-submit --executor-memory 58G --total-executor-cores 24 (... other arguments ...)

运行相同的输入需要1个多小时...我不确定问题是否在Scala或Spark配置中,所以欢迎任何帮助。

祝你好运, 奥古斯托

编辑1:某些操作的平均时间:

从S3读取文件:〜2分钟

flatMap:~11分钟

reduceByKey:> 1小时

使用的密钥是S3路径,所以它们可能会很长,不知道是否会产生影响。

编辑2:我将reduceByKey函数替换为.reduceByKey((a,b) => a),作业在10分钟后结束,因此combine函数必定存在问题< / p>

2 个答案:

答案 0 :(得分:0)

基于大部分时间都花在flatMap之后的事实,我怀疑shuffle会降低你的速度而不是CPU的利用率。您可能希望尝试使用较少的分区运行作业。您可以尝试的另一件事是将reduceByKey()替换为foldByKey(),它是关联但不可交换的,这意味着它必须在运行组合时保持RDD顺序,这可能会转化为更少的网络流量。洗牌。

答案 1 :(得分:0)

这归结为我的低级Scala编程技巧 - 当改为以下更高性能的Scala时只需15分钟:

val conceptData = spark.textFile(inputPath).repartition(24)

val result = conceptData.map(line => {val metrics = JsonUtil.fromJson[ArticleMetrics](line); (metrics.source, metrics.data.get("entities").get)})
    .flatMap(metrics => metrics._2.map(t => (t._1,(1, List(metrics._1+"\u200e"+ t._2.head)))))
    .reduceByKey((a,b) =>  (a._1 + b._1, a._2:::b._2))
    .map(t=> t._1 + "\t" + t._2._1 + "\t" + t._2._2.mkString("\u200f"))

它可能仍有待进一步改进。无论如何,感谢大家的帮助。

致以最诚挚的问候,

奥古斯托