请考虑以下代码:
case class Person(
personId: Long, name: String, ageGroup: String, gender: String,
relationshipStatus: String, country: String, state: String
)
case class PerPersonPower(personId: Long, power: Double)
val people: Dataset[Person] = ... // Around 50 million entries.
val powers: Dataset[PerPersonPower] = ... // Around 50 million entries.
people.join(powers, "personId")
.groupBy("ageGroup", "gender", "relationshipStatus", "country", "state")
.agg(
sum("power").alias("totalPower"),
count("*").alias("personCount")
)
它在具有大约100 GB RAM的群集上执行。但是,群集内存不足。我不知道该怎么做。实际上,people
由$"personId"
分区并缓存 - people.repartition($"personId").cache()
。
我可以如何优化此计算?
群集是一个vanilla Google Dataproc群集---所以它在客户端模式下使用YARN--由14个节点组成,每个节点有8 GB RAM。
答案 0 :(得分:3)
根据请求中提供的有限信息,我建议不要使用缓存并创建比默认数量更多的分区(它通常为200,但可能因群集而异) - 尝试设置{{ 1}}在你的应用程序中以1000或2000开头。它可以像spark.shuffle.partitions
那样完成。很可能你的查询命中SortMergeJoin,当前执行程序获取更多的数据,它的堆减去YARN开销。请咨询您的SparkUI for the cluster以监控和优化您的查询执行。在SQL选项卡中,您将看到关于每个阶段中正在处理的数据量的非常详细的数字,因此您将识别瓶颈并更快地修复它们。
Spark查询计划程序首先按spark.conf.set('spark.shuffle.partitions', 1000)
中定义的numberId排序PerPersonPower
和Person
,将其清除为HDFS到spark.shuffle.partitions
单独的镶木地板文件,然后创建相同的部分聚合的数量,并将其添加到结果数据框中。
您似乎正在以大约800MB(功率)加入大约18-20GB(人)的数据。如果功率稍微小一些,您可以尝试使用spark.shuffle.partitions
people.join(broadcast(powers), "personId")
,但我不建议广播大于128Mb或256Mb的数据帧。