立即注册 登录
About云-梭伦科技 返回首页

Aningorg的个人空间 https://www.aboutyun.com/?70889 [收藏] [复制] [分享] [RSS]

日志

Spark 运行内存溢出:memoryOverhead issue in Spark以及 内存不足问题:Missing an o ...

已有 3187 次阅读2018-10-31 14:08 |个人分类:spark|系统分类:大数据| spark内存问题

Spark和Hadoop做大数据应用的时候,经常遇到这个问题:

Container killed by YARN for exceeding memory limits. 16.9 GB of 16 GB physical memory used. Consider boosting spark.yarn.executor.memoryOverhead

这个错误总会使你的job夭折。它的意思是:因为超出内存限制,集群停掉了container

要做的第一个事情是增加“spark.yarn.executor.memoryOverhead”(增加spark集群中executor的内存),改为4096.为了找到这个可以修改的最大值,我通过增加这个参数的2的次幂,直到集群拒绝我提交这个job。然而,这样做并没有解决问题。

    需要思考的第二个问题是你的数据在各个分区上是否均衡!正如你所见,RDD分布在你的集群上,数据中的每一个slice/piece

/part命名为一个分区。因此分区越多,分区中的数据量就越小。如果我有200000和4的分区,那么每一个分区上包含了50000(200000/4)的图片.

    通常,从性能上考虑,你想让你的数据平衡。因为每一个并行或者分布式计算的job,希望它们在每一个节点或者线程上分布均匀。举个例子,比如你有四个分区,前三个分区负载20000张图片,最后一个分区负载了180000张图片,那么前三个分区因为图片数量少,负载较小,很容易完成这些节点上的工作,然而第四个节点,却有9倍的工作量要处理,显然前三个节点要“等待”第四个节点完成工作,随后才能将结果进行合并。因此如果各个分区上数据不平衡,job进程结束很慢。

从性能上来说,这种情况很容易导致bug。数据越多意味着需要更多的内存,这将导致内存不够的现象。出发集群kill掉这个container ,意味着job失败。

解决内存overhead的问题的方法是:重新分区(repartition)。这样可以保证每一个分区上数据的平衡。但是在实际操作中,并不是那么简单的事情,特别是用python写代码的时候,会出现一些bug,解决讨论方案见http://stackoverflow.com/questions/38799753/how-to-balance-my-data-across-the-partitions,但是scala语言解决这个问题更为Robust。其实这是spark版本较低带来的一个bug,将spark升级到2.0之后,能解决下面问题:

16/08/08 20:56:00 ERROR YarnClusterScheduler: Lost executor 68 on node.of.cluster.com: Container killed by YARN for exceeding memory limits. 12.4 GB of 12 GB physical memory used. Consider boosting spark.yarn.executor.memoryOverhead.

    另外一个重要的因素是core的数量。在内存中,减少core的个数,使得同时运行的task减少,当前的task越少,内存越充足,从另一个层面减少超内存的问题。当然,这就牺牲了快速计算的性能、cpu的使用效率。但是对于一个频频失败的job而言,能成功运行,牺牲点效率和性能还是可以接受的。

    另外,分区的数量对你的application来说也是很重要的。正如前面所述,分区越多,每个分区的数据就越少,怎么把握分区的数量并且又能让这个分区处理刚好的数据,而这需要权衡。如果你将当前的数据集分很多分区,那么每一个分区的数据就会很少,大量的分区意味着你会有很多的输出文件。这样做,看似没啥问题,输出文件多点也没啥问题。但是问题是数据源hdfs不得不控制文件空间大小,将压缩hdfs,降低其性能来确保这么多的输出文件正常运行。因此确定一个合适的分区尤为重要。

最终,能解决问题的关键点在于:

1.将"spark.yarn.executor.memoryOverhead"设置为最大值,可以考虑一下4096。这个数值一般都是2的次幂。

2.将rdd进行重新分区,这里可以考虑200k。在spark2.3的版本中,rdd成为了dateframe格式的数据。

3.将"spark.executor.cores"从8设置为4。将core的个数调小。

4.将"spark.executor.memory"从8g设置为12g。将内存调大。

还有遇到以下报错:

org.apache.spark.shuffle.MetadataFetchFailedException:Missing an output location for shuffle 5

解决方案:executor分配的内存不足,分配更多内存后解决问题,增加spark.executor.memory的参数,增大内存。


路过

雷人

握手

鲜花

鸡蛋

评论 (0 个评论)

facelist doodle 涂鸦板

您需要登录后才可以评论 登录 | 立即注册

关闭

推荐上一条 /2 下一条