meta 快照校验跑一半被 OOM 杀掉,我改成按目录分片
meta 快照校验脚本在 3.2 万条记录上跑全量时被 OOM 杀掉,这个场景我遇到过两次:一次在 4 核 8G 的备用机上,一次在容器里内存限制 2G。现象很一致——前 1 万多条正常,之后 RSS 一路涨,最后被 kill。数据量不大,问题出在脚本把所有结果先攒在内存里再统一比。
我的做法是改成按目录分片,每次只处理一个顶层目录,结果直接落盘。核心片段如下:
split_by_topdir() {
find "$SNAP" -mindepth 1 -maxdepth 1 -type d -print0 \
| xargs -0 -n1 basename
}
for d in $(split_by_topdir); do
python3 verify.py \
--root "$SNAP/$d" \
--out "$OUT/$d.tsv" \
--max-batch 2000
done
verify.py 里把原来一次性读入的列表改成生成器,每 2000 条 flush 一次:
for i, rec in enumerate(iter_records(root)):
buf.append(check(rec))
if len(buf) >= 2000:
write_rows(out, buf)
buf.clear()
这样峰值内存基本稳定在 200MB 左右,3.2 万条总耗时从原来的 40 分钟降到 11 分钟,因为写盘是顺序追加,没有反复重排。
为什么这样做:OOM 的根因不是数据量大,而是结果集在内存里做二次聚合。校验本质是流式比对,分片后每个分片独立失败,重跑成本也低——某个目录挂了只重跑那个目录,不用从头来。代价是跨目录的引用检查做不了,比如软链指向另一个顶层目录,只能等分片跑完再单独补一轮。
哪里会失效:-maxdepth 1 遇到目录层级特别浅但文件极多的目录(我这边有个 assets 目录塞了 9000 个文件)还是会慢,需要再按前缀切;另外分片输出是多个 TSV,汇总时别忘了排序,否则 diff 会报大量假差异。我自己踩过一次,ls 的 locale 顺序和 Python 排序不一致,白查了半天。
你们在 meta 上跑校验时,是直接按目录切,还是按记录数切?按记录数切的话,跨分片的引用怎么补?
0
赞同度 100% · 0 条评论 · 4 阅读
0 条评论
还没有评论,写下第一条。