PySpark作业处理~50-55GB数据集时OOM问题排查及内存疑问咨询
问题分析与解答
一、OOM错误的可能原因
- 数据倾斜:总数据量55GB看似不大,但如果某个shuffle key对应的数据量远高于平均水平(比如某个key占了几十GB),单个任务处理该分区时会直接耗尽executor的执行内存。即使总executor内存足够,单任务内存过载依然会触发OOM。
- Executor内存划分不合理:你给每个executor分配了22GB内存,但Spark默认会将executor内存划分为三部分:
- 执行+存储内存:占总executor内存的60%(约13.2GB),由
spark.memory.fraction控制 - 其他内存:占20%(约4.4GB),用于JVM本身、依赖库等开销
- 用户内存:占20%(约4.4GB),用于用户自定义数据结构等
如果任务的执行内存需求超过13.2GB的限制,就会引发OOM。
- 执行+存储内存:占总executor内存的60%(约13.2GB),由
- Shuffle阶段内存压力叠加:每个executor并行运行4个任务,若这些任务同时处于shuffle阶段(比如shuffle write时生成临时文件、shuffle read时拉取并合并数据),多个任务的内存开销会累积,超过执行内存的阈值。即使单个任务的内存需求不高,并行任务的叠加也可能触发OOM。
- Delta表读取的隐藏开销:Delta表的元数据处理、版本合并、小文件合并等操作可能导致实际处理的数据量远超标称的55GB;如果谓词下推失效,Spark会读取更多无关数据,增加内存压力。
- JVM GC配置问题:若JVM垃圾回收策略不合理(比如默认的串行GC),内存无法及时释放,导致内存碎片或堆积,最终引发OOM。
二、分区内存占用的疑问解答
不需要将executor分配的13个分区一次性全部放入内存。Spark的任务调度逻辑是:
- 每个executor的并行任务数等于核数(你的配置是4核,同时运行4个任务),同一时间仅会将这4个任务对应的分区数据加载到内存处理,其余待处理的分区会留在磁盘上等待调度。
- 但需要注意两个例外场景:
- 若开启了数据缓存(
cache()/persist()),处理完成的分区数据会被缓存到executor的存储内存中,若缓存的分区过多,会占用大量内存。 - 当shuffle内存不足时,Spark会将中间数据spill到磁盘(默认开启
spark.shuffle.spill),但如果spill速度跟不上数据生成速度,依然会导致内存溢出。
- 若开启了数据缓存(
内容的提问来源于stack exchange,提问作者user16798185
相关产品推荐
相关产品推荐

