Linux 定时任务完全指南:crontab 进阶与 systemd timer 实战
定时任务是运维自动化的基石。数据库备份、日志清理、定时报告、缓存预热——这些都离不开定时执行的能力。本文深度讲解 crontab 的进阶用法,以及更现代的 systemd timer,让你的定时任务更可靠、更可观测。
一、crontab 语法深度解析
# crontab 时间字段: ┌───────────── 分钟 (0-59) │ ┌───────────── 小时 (0-23) │ │ ┌───────────── 日期 (1-31) │ │ │ ┌───────────── 月份 (1-12 或 JAN-DEC) │ │ │ │ ┌───────────── 星期 (0-7, 0和7都是周日,或 SUN-SAT) │ │ │ │ │ * * * * * /path/to/command # 常用示例 0 2 * * * # 每天凌晨2点 0 2 * * 1 # 每周一凌晨2点 */5 * * * * # 每5分钟 0 */4 * * * # 每4小时整点 0 2 1,15 * * # 每月1日和15日凌晨2点 0 2 * * 1-5 # 工作日(周一到周五)凌晨2点 @reboot # 系统重启后执行一次 @daily # 等同于 0 0 * * * @weekly # 等同于 0 0 * * 0
二、crontab 常用操作
crontab -l # 列出当前用户的定时任务 crontab -e # 编辑(会打开 vi/nano) crontab -r # 删除所有定时任务(谨慎!) crontab -u nginx -l # 查看 nginx 用户的定时任务(需要 root) # 系统级 crontab(针对服务运行,需指定用户) # 文件:/etc/crontab(有 username 字段) # 目录:/etc/cron.d/(推荐:独立文件,方便管理) # 示例:/etc/cron.d/myapp 0 2 * * * root /opt/myapp/scripts/backup.sh >> /var/log/myapp/backup.log 2>&1
三、crontab 的七个常见坑
坑1:没有加载环境变量
# crontab 运行时的 PATH 非常有限,很多命令找不到 # 解决:在脚本或 crontab 中显式设置 PATH PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin 0 2 * * * /opt/backup/run.sh
坑2:没有日志,出错了不知道
# 正确做法:重定向标准输出和错误 0 2 * * * /opt/backup.sh >> /var/log/backup.log 2>&1 # 或者同时发送邮件通知(需要配置 MTA) MAILTO=ops@example.com 0 2 * * * /opt/backup.sh
坑3:时区问题
# crontab 使用系统时区,检查系统时区 timedatectl # 临时修改 crontab 的时区(不改系统时区) CRON_TZ=Asia/Shanghai 0 2 * * * /opt/backup.sh
坑4:并发执行
# 如果上一次任务还没跑完,下一次又开始了(典型于长时间任务) # 使用文件锁防止并发 0 * * * * flock -n /tmp/backup.lock /opt/backup.sh || echo "上次任务未完成,跳过"
坑5:相对路径问题
# 错误:相对路径在 crontab 里通常无法工作 0 2 * * * ./scripts/backup.sh # ❌ # 正确:始终使用绝对路径 0 2 * * * /opt/myapp/scripts/backup.sh # ✅
四、systemd Timer:现代化定时任务
相比 crontab,systemd timer 的优势:
- 任务输出自动写入 journald,可用 journalctl 查看历史
- 支持 Persistent=true(机器关机期间错过的任务开机后补跑)
- 可以设置随机延迟(RandomizedDelaySec),分散高峰压力
- 任务之间可以定义依赖关系
# 示例:每天凌晨2点执行数据库备份 # 步骤1:创建 service 文件 # /etc/systemd/system/db-backup.service [Unit] Description=Database Daily Backup After=mysql.service [Service] Type=oneshot # 执行完就退出 User=backup # 用专门的低权限用户执行 ExecStart=/opt/scripts/db_backup.sh StandardOutput=journal StandardError=journal # 步骤2:创建 timer 文件 # /etc/systemd/system/db-backup.timer [Unit] Description=Run DB Backup Daily at 2:00 [Timer] OnCalendar=*-*-* 02:00:00 # 每天凌晨2点 RandomizedDelaySec=300 # 在2:00-2:05之间随机启动(避免多台服务器同时备份) Persistent=true # 错过了开机后立即补跑 [Install] WantedBy=timers.target # 步骤3:启用 systemctl daemon-reload systemctl enable --now db-backup.timer systemctl list-timers db-backup.timer # 查看下次执行时间 journalctl -u db-backup.service -f # 查看备份日志
五、一键检查所有定时任务
# 查看当前用户 crontab crontab -l # 查看 /etc/cron.d/ 下的任务 ls -la /etc/cron.d/ # 查看系统 crontab cat /etc/crontab # 查看所有 systemd timer systemctl list-timers --all # 查看最近 timer 执行记录 journalctl -u "*.timer" --since "24 hours ago" --no-pager
总结
掌握 crontab 进阶用法(显式设置 PATH、添加日志、使用 flock 防并发)可以解决 90% 的定时任务问题。对于新项目,推荐使用 systemd timer,获得更好的可观测性和可靠性。所有定时任务都要有日志输出,没有日志就没有可观测性,出了问题无从追查。
