spark内存管理说明

spark内存有几种不同的用途,理解并调优spark的内存使用方法有利于帮助优化spark的应用。在各个执行器中,内存有如下几种用途。

1.RDD存储

    当调用persist或cache方法时,这个RDD的分区会被存储到缓存区中。spark会根据spark.storage.memoryFraction限制用来缓存的内存占整个jvm堆空间的大小。如果超出限制,旧的分区数据会被移出内存。

2.数据混洗与聚合的缓存区

      当进行数据混洗操作时,spark会创建出一些中间缓存区来存储数据混洗输出的数据。这些缓存区用来存储聚合操作的中间结果,以及数据混洗操作中直接输出的缓存数据。spark会根据spark.shuffle.memoryFraction限定这种缓存区内存占总内存的比例。

3.用户代码

spark可以执行任意的用户代码,故用户的函数可以自行申请大量内存。用户代码可以访问jvm堆空间中除分配给RDD存储和数据混洗存储以外的全部剩余空间。

        在默认情况下,Spark 会使用 60%的空间来存储 RDD,20% 存储数据混洗操作产生的数 据,剩下的 20% 留给用户程序。用户可以自行调节这些选项来追求更好的性能表现。如果 用户代码中分配了大量的对象,那么降低 RDD 存储和数据混洗存储所占用的空间可以有 效避免程序内存不足的情况。

       除了调整内存各区域比例,我们还可以为一些工作负载改进缓存行为的某些要素。Spark默认的 cache() 操作会以 MEMORY_ONLY 的存储等级持久化数据。这意味着如果缓存新的RDD 分区时空间不够,旧的分区就会直接被删除。当用到这些分区数据时,再进行重算。 所以有时以 MEMORY_AND_DISK 的存储等级调用 persist() 方法会获得更好的效果,因为在这 种存储等级下,内存中放不下的旧分区会被写入磁盘,当再次需要用到的时候再从磁盘上 读取回来。这样的代价有可能比重算各分区要低很多,也可以带来更稳定的性能表现。当RDD 分区的重算代价很大(比如从数据库中读取数据)时,这种设置尤其有用。

     对于默认缓存策略的另一个改进是缓存序列化后的对象而非直接缓存。我们可以通过MEMORY_ONLY_SER 或者 MEMORY_AND_DISK_SER 的存储等级来实现这一点。缓存序列化后的对 象会使缓存过程变慢,因为序列化对象也会消耗一些代价,不过这可以显著减少 JVM 的 垃圾回收时间,因为很多独立的记录现在可以作为单个序列化的缓存而存储。垃圾回收的 代价与堆里的对象数目相关,而不是和数据的字节数相关。这种缓存方式会把大量对象序 列化为一个巨大的缓存区对象。如果你需要以对象的形式缓存大量数据(比如数 GB 的数 据),或者是注意到了长时间的垃圾回收暂停,可以考虑配置这个选项。这些暂停时间可 以在应用用户界面中显示的每个任务的垃圾回收时间那一栏看到。

    

猜你喜欢

转载自blog.csdn.net/sujins5288/article/details/93191258