Hadoop 内存中TB文件的Spark执行

Hadoop 内存中TB文件的Spark执行,hadoop,apache-spark,pyspark,Hadoop,Apache Spark,Pyspark,假设我有一个Tb的数据文件。 十节点集群中的每个节点内存为3GB 我想用spark处理文件。 但是1 TB的内存是如何存储的呢 它会抛出内存不足异常吗 它是如何工作的?默认情况下,存储级别仅为内存,它将尝试将数据放入内存中。如果数据无法装入内存,则会出现内存不足的问题 它支持其他存储级别,如内存和磁盘、仅磁盘等。您可以通过浏览了解不同的存储级别。您可以在RDD上调用persist函数以使用不同的存储级别 正如Thilo所提到的,Spark不需要加载内存中的所有内容就可以处理它。这是因为Spark

假设我有一个Tb的数据文件。 十节点集群中的每个节点内存为3GB

我想用spark处理文件。 但是1 TB的内存是如何存储的呢

它会抛出内存不足异常吗


它是如何工作的?

默认情况下,存储级别仅为内存,它将尝试将数据放入内存中。如果数据无法装入内存,则会出现内存不足的问题


它支持其他存储级别,如内存和磁盘、仅磁盘等。您可以通过浏览了解不同的存储级别。您可以在RDD上调用persist函数以使用不同的存储级别

正如Thilo所提到的,Spark不需要加载内存中的所有内容就可以处理它。这是因为Spark将数据划分为更小的块,并分别对这些块进行操作。分区的数量及其大小取决于以下几点:

  • 文件存储的位置。Spark最常用的选项已经将文件存储在一堆块中,而不是作为单个大数据块。例如,如果存储在HDFS中,则默认情况下,这些块为64MB,并且这些块分布(和复制)在您的节点上。使用存储在S3中的文件,您将获得32MB的块。这是由Hadoop
    文件系统定义的,该文件系统用于读取文件,并应用于Spark使用Hadoop读取的其他文件系统中的文件
  • 你所做的任何重新划分。您可以在RDD或数据帧上调用
    repartition(N)
    coalesce(N)
    ,以更改分区的数量和大小
    coalesce
    是减少数据数量的首选方法,而不必在节点间乱序数据,而
    重新分区
    允许您指定一种新的数据拆分方法,即更好地控制在同一节点上处理的数据部分
  • 您可以执行一些更高级的转换。例如,配置设置
    spark.sql.shuffle.partitions
    ,默认设置为200,确定由联接和聚合产生的
    DataFrame
    将有多少个分区
缓存 前面的部分只涉及Spark中数据的标准处理,但我觉得您可能会有错误的想法,因为Spark被宣传为“内存中”,所以我想稍微说明一下。默认情况下,Spark中没有比任何其他数据处理工具更“在内存中”的了:一个简单的例子是
sc.textFile(foo).map(mapFunc).saveTextFile(bar)
读取一个文件(逐块并分布在节点上),在内存中进行映射(就像任何计算机程序一样),然后再次将其保存到存储器中。Spark对内存的使用在以下方面变得更加有趣(在Scala中,因为我更熟悉它,但在Python中,概念和方法名称完全相同):

val rdd=sc.textFile(foo)
//做一些预处理,比如分析行
val preprocessed=rdd.map(preprocessFunc)
//告诉Spark缓存预处理的数据(默认情况下在内存中)
预处理的.cache()
//执行一些映射并保存输出
预处理的.map(mapFunc1).saveTextFile(outFile1)
//执行不同的映射并保存到其他地方
预处理的.map(mapFunc2).saveTextFile(outFile2)
这里的想法是使用
cache();默认情况下,Spark不保存任何中间结果,而是计算每个单独操作的完整链,其中“操作”是
saveTextFile
调用

我之所以说“可能”,是因为实际缓存数据的能力受到节点内存的限制。Spark为缓存存储保留一定数量的内存,与工作内存分开(请参见如何管理这些内存部分的大小),并且只能缓存该数量的内存

但是,根据分区的不同,它可能会更少。假设3个节点中的每个节点上都有2GB的存储内存,
预处理中的数据为6GB。如果此数据有3个分区,它将非常适合,并且将从内存加载到
mapFunc2
的所有输入数据。但是如果你有4个分区,每个分区1.5Gb,那么每个节点上只能缓存1个分区;第四个分区不适合每台机器上剩余的0.5GB,因此必须重新计算该分区以进行第二次映射,并且只有3/4的预处理数据将从内存中读取

因此,从这个意义上讲,最好有许多小分区,以使缓存尽可能高效,但这可能有其他缺点:如果碰巧使用细粒度模式的Mesos,则会有更多的开销、巨大的延迟,以及大量的小输出文件(如果在保存之前没有合并),因为Spark会将每个分区保存为单独的文件


正如Durga提到的,也有可能将不适合内存的数据溢出到磁盘,您可以按照他的链接进行操作:)

很多处理都可以完成,而无需立即将整个文件读入内存。你到底在执行什么操作?1)Spark可以将30GB缓存到RAM,其余的将从磁盘读取。2) 也许你不需要缓存你的数据,你想做什么呢?事实并非如此,spark会尝试重新计算,如果所有的数据至少不能放入RDD文档中,这是最新的行为-内存只将RDD作为反序列化Java对象存储在JVM中。如果RDD不适合内存,则某些分区将不会被缓存,并且会在每次需要时动态重新计算。这是默认级别。