这类问题我又碰上了一次。一台 4 核 8G 的 CentOS 7 上有四十多条 crontab,全部写成 0 3 * * *,凌晨三点 load 冲到 30,监控连发三条告警,几个 tar 任务互相等 IO 最后超时失败。

排查方向其实有限,先把可能性排一排。所有任务同一分钟启动,瞬时并发远超 CPU 核数,队列被拉长;任务都是 tar 和 rsync 这类 IO 密集型,磁盘队列一打满全部变慢;脚本没有超时和失败退出,卡住的任务一直占着资源。

第一件事是列出同一时刻的任务

crontab -l | awk '$1=="0" && $2=="3"'

然后在脚本开头加随机延迟摊开

sleep $((RANDOM % 1800)); exec /opt/job.sh

接着改用 timer 并加随机抖动

OnCalendar=*-*-* 03:00:00  RandomizedDelaySec=1800

给每个任务加硬超时

timeout 1800 /opt/job.sh >> /var/log/job.log 2>&1

报错是间歇性的,我蹲守了半小时才抓到一次完整现场。

恢复的判定其实很直接。次日凌晨 load 峰值低于核数的 1.5 倍,各任务日志里的开始时间分散在半小时内,失败计数为 0。

任务多的机器要把执行时间当成资源来排,磁盘密集的还要错开;用 timer 的 RandomizedDelaySec 比在脚本里 sleep 更可控。这类问题最好一次改到位,反复小改反而容易把原因搅混。

作者 9823189