关于1
Spark 使用分布式数据结构,如 RDD 和 Dataset(以及 2.0 之前的 Dataframe)。以下是您应该了解的有关此数据结构的事实,以回答您的问题:
- 所有的转换操作,如(映射、过滤器等)都是惰性的。这意味着除非您需要操作的具体结果(如减少、折叠或将结果保存到某个文件),否则不会执行读取。
- 在 HDFS 上处理文件时,Spark 使用文件分区进行操作。分区是可以处理的最小逻辑批数据。通常一个分区等于一个 HDFS 块,并且分区的总数永远不能少于一个文件中的块数。常见的(和默认的)HDFS 块大小为 128Mb
- RDD 和 Dataset 中的所有实际计算(包括从 HDFS 读取)都在 executors 内部执行,而不是在驱动程序上执行。Driver 创建 DAG 和逻辑执行计划,并将任务分配给 executor 以进行进一步处理。
- 每个执行程序针对特定的数据分区运行先前分配的任务。因此,通常如果您只为执行程序分配一个核心,它会同时处理不超过 128Mb(默认 HDFS 块大小)的数据。
所以基本上当你调用时sc.textFile
没有实际的阅读发生。所有提到的事实都解释了为什么在处理 20 Tb 的数据时也不会发生 OOM。
有一些特殊情况,例如 iejoin
操作。但即使在这种情况下,所有执行程序都会将它们的中间结果刷新到本地磁盘以进行进一步处理。
关于2
在 JDBC 的情况下,您可以决定您的表有多少个分区。并在表中选择适当的分区键,将数据正确拆分为分区。由您决定同时将多少数据加载到内存中。
关于3
本地文件的块大小由fs.local.block.size
属性控制(我猜默认为 32Mb)。因此它与 1(HDFS 文件)基本相同,只是您将从一台机器和一个物理磁盘驱动器读取所有数据(这在 20TB 文件的情况下效率极低)。