You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Spark ContextCleaner未清理usercache blockmgr目录下的溢写数据

Spark Shuffle文件堆积:ContextCleaner标记清理但磁盘文件未删除的排查与解决

问题场景

  • Spark应用重复执行「加载Dataset→关联其他Dataset→写入输出」流程,未启用任何Dataset缓存
  • 运行2-3小时后,usercache/something/appcache/application_1696806712764_495852/blockmgr-something/目录被大量shuffle.data和shuffle.index文件填满
  • 已尝试以下操作但无效:
    • 手动将Dataset置为null以消除引用
    • 调用dataset.unpersist()(虽未使用缓存)
    • Driver端手动触发GC
  • 日志显示:
    • Driver端ContextCleaner已标记并完成Shuffle清理:
      23/11/01 20:23:36 DEBUG ContextCleaner: Got cleaning task CleanShuffle(4)
      23/11/01 20:23:36 DEBUG ContextCleaner: Cleaning shuffle 4
      23/11/01 20:23:36 DEBUG ContextCleaner: Cleaned shuffle 4
      
    • Executor端BlockManager返回删除成功:
      23/11/02 10:41:17 DEBUG BlockManagerStorageEndpoint: removing shuffle 17
      23/11/02 10:41:17 DEBUG BlockManagerStorageEndpoint: Done removing shuffle 17, response is true
      23/11/02 10:41:17 DEBUG BlockManagerStorageEndpoint: Sent response: true to somehostname:24399
      
    但磁盘上的Shuffle文件仍未被删除。

可能原因

  1. Shuffle文件延迟删除机制:Spark默认会保留Shuffle文件一段时间,若开启外部Shuffle服务,清理由服务节点负责,存在周期延迟
  2. Executor物理删除未执行:BlockManager日志的「删除成功」仅代表逻辑标记完成,实际物理删除可能因磁盘IO阻塞、文件句柄被占用而未执行
  3. 隐式引用残留:手动置Dataset为null后,仍可能存在广播变量、未关闭的流、Job状态对象等隐式引用,导致Shuffle依赖未被真正回收
  4. Spark版本Bug:部分旧版本(如Spark 2.3.x之前)存在Shuffle文件清理逻辑的已知Bug

解决方案

1. 调整Shuffle清理配置

  • 若开启了外部Shuffle服务(spark.shuffle.service.enabled=true):
    • 缩短清理周期:设置spark.shuffle.service.cleanup.interval=10m(默认30分钟)
  • 取消延迟删除:添加配置spark.shuffle.file.deleteDelay=0(默认10分钟),让Shuffle文件在标记后立即删除
  • 若不需要外部Shuffle服务,可关闭它:spark.shuffle.service.enabled=false,由Executor自行负责清理

2. 排查文件句柄占用

在Executor节点执行以下命令,检查是否有进程持有Shuffle文件的句柄:

lsof | grep shuffle

若存在未释放的句柄,排查是否是应用残留线程、第三方库导致的句柄泄漏。

3. 升级Spark版本

如果使用Spark 2.3.x及更早版本,建议升级到2.3.x或更高版本,修复旧版本中存在的Shuffle文件泄漏问题;Spark 3.x用户可查阅官方Release Notes,确认是否存在相关已知Issue并升级到对应修复版本。

4. 优化应用执行逻辑

  • 将重复执行的流程封装为独立Job,确保每个Job执行完成后,相关Shuffle依赖能被完全回收
  • 避免Driver端长时间持有Dataset引用,每个流程结束后可尝试调用System.gc()并短暂休眠(如Thread.sleep(1000)),给GC足够时间回收引用(生产环境不建议依赖手动GC,仅用于排查)

5. 验证实际清理日志

在Executor端添加日志配置:

log4j.logger.org.apache.spark.storage.DiskBlockManager=DEBUG

查看DiskBlockManager的日志,确认是否执行了物理删除操作,是否存在报错或跳过的情况。

内容的提问来源于stack exchange,提问作者best wishes

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.07 06:04:59