合并排序连接在 Spark 中如何工作以及为什么会抛出 OOM?

Mia*_*ach 6 apache-spark

我想深入了解Spark中合并排序连接的概念。我理解总体思路:这与合并排序算法的方法相同:采用 2 个排序数据集,比较第一行,写入最小的行,重复。我也了解如何实现分布式合并排序。

但我不明白它是如何在 Spark 中实现分区和执行器概念的。

这是我的看法。

  1. 鉴于我需要连接 2 个表 A 和 B。表是通过 Spark SQL 从 Hive 读取的,如果这很重要的话。
  2. 默认情况下 Spark 使用 200 个分区。
  3. 然后 Spark 将计算连接键范围(从 minKey(A,B) 到 maxKey(A,B) )并将其分成 200 个部分。两个数据集均按关键范围分为 200 个部分:A 分区和 B 分区。
  4. 与相同键相关的每个 A 分区和每个 B 分区都被发送到同一个执行器,并在那里彼此分开排序。
  5. 现在,200 个执行程序可以加入 200 个 A 分区和 200 个 B 分区,并保证它们共享相同的密钥范围。
  6. 连接通过合并排序算法进行:从 A 分区中获取最小键,与 B 分区中的最小键进行比较,写入匹配或迭代。
  7. 最后,我有 200 个已连接的数据分区。

是否有意义?

问题: 按键倾斜。如果某个键范围包含数据集键的 50%,则某些执行器将受到影响,因为太多行将进入同一分区。当尝试对内存中太大的 A 分区或 B 分区进行排序时,它甚至可能因 OOM 而失败(我不明白为什么 Spark 无法像 Hadoop 那样对磁盘溢出进行排序?..)或者它可能会失败,因为它尝试读取两个分区都放入内存中进行连接?

所以,这是我的猜测。您能纠正我并帮助理解 Spark 的工作方式吗?

小智 1

这是 MPP 数据库上联接的常见问题,Spark 也不例外。正如您所说,要执行联接,同一联接键值的所有数据必须位于同一位置,因此,如果联接键上有偏斜分布,则数据分布会偏斜,并且一个节点会过载。

如果连接的一侧很小,您可以使用地图侧连接。Spark 查询规划器确实应该为您执行此操作,但它是可调的 - 不确定它的最新程度,但它看起来很有用。

您是否对两个表都运行了ANALYZE TABLE

如果两侧都有一个不会破坏连接语义的键,您可以将其包含在连接中。