Spark内存优化

内存优化有三个方面的考虑:对象所占用的内存(或许大家都希望将所有数据都加载到内存),优化Spark的缓存以及内存回收(GC)所占用的开销。

1,对象所占用的内存

首先要估算对象所占用的内存,然后从两方面进行改进–通过改变数据结构或者采用序列化的方式。

1.1,确定内存消耗

创建一个RDD,然后将其放入缓存,最后阅读驱动程序中SparkContext的日志。日志会告诉我们每一部分所占用的内存大小,可以收集该类信息以确定RDD消耗内存的最终大小。

1.2,优化数据结构

减少内存使用的第一条路径是避免使用一些额外开销的java特性,比如:

  • 使用对象数组以及类型数组代替java或者Scala集合类
  • 尽可能的避免采用还有指针的嵌套数据结构来保存小对象
  • 考虑采用数字ID或者枚举类型替代String类型的主键
  • 如果内存少于32GB,设置JVM参数 -XX:+UseCompressedOps以便将8字节指针修改成4字节。同时设置-XX:+UseCompressStrings以便采用8比特来编码每一个ASCII字符。将这些选项添加到spark-env.sh中。

1.3,序列化

经过上述优化,如果对象还是太大以至于不能有效存放,还有一个减少内存使用的简单方法-----序列化。将RDD序列化以后再进行缓存。

2,优化Spark的缓存

3,优化GC

如果Spark程序产生大量的RDD数据,JVM内存回收就可能会成为问题(通常,如果只需要进行一次RDD读取然后进行操作是不会带来问题的)。当需要回收就对象以便为新对象腾内存空间时,JVM需要跟踪对象以确定那些对象可回收。

3.1,估算gc的影响

优化gc的第一步是获取一些统计信息,包括gc的频率,耗费的时间等。为了获取这些信息,可以把参数 --verbose:gc,–XX:+PrintGCDetails --XX:PrintGCTimeStamps添加到spark-env.sh中。设置完成以后,Spark作业运行时,我们可以在日志中看到每一次内存惠州的信息。

3.2, 优化缓存大小

用多大的内存缓存RDD是内存回收一个非常重要的参数配置。默认情况下,spark采用运行内存(executor.memory)的60%的空间来进行缓存,这表明在任务创建期间,有40%的内存可以用来进行对象的创建。如果任务运行速度变慢且JVM频繁进行gc,或者内存空间不足,那么降低缓存大小设置可以减少内存消耗。为了将缓存大小修改为50%,我们可以调用方法System.setProperty(“spark.storage.memoryFraction”,“0.5”)。结合序列化缓存,使用较小的缓存足够解决内存回收的大部分问题。

3.3,gc高级优化

结合jvm内存规划,spark gc优化的目标是确保只有长时间存活的RDD才能保存到老年代区域;同时,新生代区域足够大以保存生命周期比较短的对象。这样,在任务执行期间可以避免执行full gc。步骤如下:

  • 通过收集gc信息检查内存回收是不是过于频繁。如果人任务结束之前执行了很多次full gc,则表示任务执行的内存空间不足。
  • 在打印的内存回收信息中,如果老年代接近消耗殆尽,那么减少用于缓存的内存空间。这可以通过属性spark.storage.memoryFraction来完成。减少缓存对象以提高执行速度是非常值得的。
  • 如果有过多的minor GC而不是full gc,那么Eden分配更大的内存是有益的。可以为Eden分配大于任务执行所需要的内存空间。如果Eden的大小确定为E,那么可以通过-Xmn=4/3*E来设置新生代的大小(将内存扩大到4/3是考虑到survivor所需要的的空间)。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值