Oh spark,贫穷限制了我的想象力

两天前写好了一个一千行的spark sql,测试好了准备把结果写到s3上,结果写了两天没写进去,今天终于搞定了,特此记录。 事件回顾 这条sql不算复杂,左表10000+行,来回join两张千万级的表和两张不到一亿的表。中间所产生的内存开销为28.5G(从spark UI的input字段得出)。查询结果可以show出来,可以limit 100,但是limit 1000就不行了,更不能写到s3上。 报错信息是: spark.java.lang.OutOfMemoryError: Unable to acquire 44 bytes of memory, got 0 at org.apache.spark.memory.MemoryConsumer.allocatePage(MemoryConsumer.java:127) 我跟这个error纠结了两天。。。查了文档,jira,各种查,各种参数各种试,总是在最后一个stage弹出这个error。 spark版本是2.2.0,使用的是aws的emr,因为是28.5g的数据,我就开了core nodes是5台8 cores, 15g mem的cluster,这里的可用内存大概是55g,我心想怎么也该够用了吧。 今天试了2.0.0和2.1.1版本,都得出了相同的错误。还咨询了之前搞spark的同事,依然没搞定。 当我第三次阅读doc时,我隐约发现了问题所在。 什么是storage 这里就不介绍spark的内存管理了,贴个简介。 简单理解storage,spark是把内存当硬盘用的,来持久化rdd,所以大多数情况,storage就是内存,但是当内存不够用的时候,就会出现spill to disk的情况,也就是写硬盘。所以如果storage足够大,内容就会被保存在内存中,反之就会spill to disk,当太小时,可能会出现频繁spill to disk,从而影响效率。 那么,executor的内存怎么办呢 executor会占用另外一部分内存,但是我现在不确定executor会不会spill to disk。至少凭借现在的现象观测下来,executor在shuffle write的时候是不会spill to disk的。这里也好理解,毕竟shuffle是要在executors之间转移的。 两个参数spark.memory.fraction和spark.memory.storageFraction spark.memory.fraction默认是0.6 Fraction of (heap space - 300MB) used for execution and storage. The lower this is, the more frequently spills and cached data eviction occur. The purpose of this config is to set aside memory for internal metadata, user data structures, and imprecise size estimation in the case of sparse, unusually large records....

December 15, 2017 · 1 min · magicalne