[英]Cross join between two large datasets in Spark
我有 2 个大型数据集。 第一个数据集包含大约 1.3 亿个条目。
第二个数据集包含大约 40000 个条目。 数据是从 MySQL 表中获取的。
我需要进行交叉连接,但我得到了
java.sql.SQLException: GC overhead limit exceeded
在 Scala 中执行此操作的最佳技术是什么?
以下是我的代码片段:
val df1 = (spark.read.jdbc(jdbcURL,configurationLoader.mysql_table1,"id",100,100000,40, MySqlConnection.getConnectionProperties))
val df2 = (spark.read.jdbc(jdbcURL,configurationLoader.mysql_table2, MySqlConnection.getConnectionProperties))
val df2Cache = df2.repartition(40).cache()
val crossProduct = df1.join(df2Cache)
df1 是较大的数据集,df2 是较小的数据集。
130M*40K = 52 万亿条记录是存储这些数据所需的 52 TB 内存,如果我们假设每条记录是 1 个字节,这肯定是不正确的。 如果它多达 64 个字节(我认为这也是一个非常保守的估计),那么您需要 3.32 PB (!) 的内存来存储数据。 这是一个非常大的数量,因此除非您有一个非常大的集群和该集群内的非常快的网络,否则您可能需要重新考虑您的算法以使其工作。
话虽如此,当您join
两个 SQL 数据集/数据帧时,Spark 用于存储连接结果的分区数由spark.sql.shuffle.partitions
属性控制(请参阅此处)。 您可能希望将其设置为一个非常大的数字,并将执行程序的数量设置为您能做到的最大数量。 然后,您也许可以将处理运行到最后。
此外,您可能需要查看spark.shuffle.minNumPartitionsToHighlyCompress
选项; 如果您将其设置为少于 shuffle 分区的数量,您可能会再次获得内存提升。 请注意,此选项是一个硬编码常量,直到最近的 Spark 版本才设置为 2000,因此根据您的环境,您只需将spark.sql.shuffle.partitions
设置为大于 2000 的数字即可使用它。
同意 Vladimir 的观点,想加分。
看到MapStatus集spark.sql.shuffle.partitions
它2001
( 旧办法)(默认值是200)。
新方法( spark.shuffle.minNumPartitionsToHighlyCompress
)正如 Vladimir 在回答中提到的那样。
为什么会有这种变化? : MapStatus 有 2000 个硬编码 SPARK-24519
它将应用不同的算法来处理
def apply(loc: BlockManagerId, uncompressedSizes: Array[Long]): MapStatus = {
if (uncompressedSizes.length > minPartitionsToUseHighlyCompressMapStatus) {
HighlyCompressedMapStatus(loc, uncompressedSizes)
} else {
new CompressedMapStatus(loc, uncompressedSizes)
}
}
HighlyCompressedMapStatus
:
一个 MapStatus 实现,用于存储比 spark.shuffle.accurateBlockThreshold 大的大块的准确大小。 它存储其他非空块的平均大小,以及用于跟踪哪些块是空的位图。
spark.shuffle.accurateBlockThreshold - 看这里:当我们在HighlyCompressedMapStatus
压缩 shuffle 块的大小时,如果它高于此配置,我们将准确记录大小。 这有助于通过在获取 shuffle 块时避免低估 shuffle 块大小来防止 OOM。
CompressedMapStatus
:
跟踪每个块大小的 MapStatus 实现。 每个块的大小使用单个字节表示。
还设置为您的spark-submit
--conf spark.yarn.executor.memoryOverhead=<10% of executor memory> -- conf spark.shuffle.compress=true --conf spark.shuffle.spill.compress=true
在这两种情况下,压缩都将使用spark.io.compression.codec
结论:大型任务应该使用
HighlyCompressedMapStatus
并且执行程序内存开销可能是执行程序内存的10%。
此外,看看 火花内存调整
将 SPARK_EXECUTOR_MEMORY 增加到更高的值并重新分区到更多分区
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.