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
- Driver端ContextCleaner已标记并完成Shuffle清理:
可能原因
- Shuffle文件延迟删除机制:Spark默认会保留Shuffle文件一段时间,若开启外部Shuffle服务,清理由服务节点负责,存在周期延迟
- Executor物理删除未执行:BlockManager日志的「删除成功」仅代表逻辑标记完成,实际物理删除可能因磁盘IO阻塞、文件句柄被占用而未执行
- 隐式引用残留:手动置Dataset为null后,仍可能存在广播变量、未关闭的流、Job状态对象等隐式引用,导致Shuffle依赖未被真正回收
- 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
相关产品推荐
相关产品推荐

