这类问题我又碰上了一次。一台 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 更可控。这类问题最好一次改到位,反复小改反而容易把原因搅混。
