了解 Spark 分区

Understanding Spark partitioning

我正在尝试了解 Spark 如何对数据进行分区。假设我有一个如图所示的执行 DAG(橙色框是阶段)。如果 RDD 没有分区,这两个 groupByjoin 操作应该非常繁重。

那么对 P1、P2、P3 和 P4 使用 .partitonBy(new HashPartitioner(properValue)) 以避免随机播放是否明智?对现有 RDD 进行分区的成本是多少?什么时候不适合对现有的 RDD 进行分区?如果我不指定分区程序,Spark 不会自动对我的数据进行分区吗?

谢谢

通过先发制人地应用 partitionBy,您无法避免随机播放。你只要把它推到另一个地方。如果分区的 RDD 被多次重用,这可能是个好主意,但对于一次性连接你什么也得不到。

Doesn't Spark partition my data automatically if I don't specify a partitioner?

它将分区(a.k.a.shuffle)你的数据成为连接的一部分)和随后的groupBy(除非你保持相同的键并使用保留分区的转换)。

tl;dr 分别回答你的问题: 可以的话最好一开始就分区;可能小于不分区;无论如何,您的 RDD 以一种或另一种方式进行了分区;是的

这是一个相当宽泛的问题。它占据了我们课程的很大一部分!但是,让我们尝试在不写小说的情况下尽可能多地解决分区问题。

如您所知,使用像 Spark 这样的工具的主要原因是您有太多数据需要在一台机器上分析,而风扇的声音又不像喷气发动机。数据分布在集群中所有机器上的所有内核中,所以是的,有一个默认分区——根据数据。请记住,数据已经是静态分布的(在 HDFS、HBase 等中),因此 Spark 默认情况下只是根据相同的策略进行分区,以将数据保存在它们已经存在的机器上——默认分区数相等到集群上的核心数。您可以通过配置 spark.default.parallelism 覆盖此默认数量,并且您希望此数量为每台机器每个内核 2-3 个。

但是,通常您希望属于一起的数据(例如,具有相同键的数据,其中 HashPartitioner 适用)位于同一分区中,而不管它们从哪里开始,因为为了您的分析,并尽量减少以后的洗牌。 Spark 还提供了 RangePartitioner,或者您可以很容易地根据自己的需要推出自己的。但是你是对的,从默认分区到自定义分区有一个前期的洗牌成本;这几乎总是值得的。

通常明智的做法是在一开始就进行分区(而不是用 partitionBy 延迟不可避免的事情),然后 repartition 如果以后需要的话。稍后您可能会选择 coalesce even,这会导致中间洗牌,以减少分区数量并可能使一些机器和核心闲置,因为网络 IO 的收益(在前期成本之后)大于损失CPU 的力量。

(我能想到的唯一一开始不分区的情况——因为你不能——是当你的数据源是一个压缩文件时。)

另请注意,您可以使用 mapPartitionsmapPartitionsWithIndex 在地图转换期间保留分区。

最后,请记住,在扩大规模的过程中试验分析时,您可以使用以下诊断功能:

  • toDebugString 查看 RDDs
  • 的血统
  • getNumPartitions 令人震惊地得到分区数
  • glom 看清楚你的数据是如何分区的

如果你原谅无耻的插件,这些就是我们在 Analytics with Apache Spark 中讨论的事情。我们希望尽快有在线版本。