Linux 定时任务进阶:用 systemd timer 替代 cron 的实战做法
Linux 定时任务进阶:用 systemd timer 替代 cron 的实战做法
用过 Linux 服务器的人,大多用 cron 写过定时任务:每天凌晨备份、每小时清理日志、每周重启一次服务。一行 0 2 * * * /path/backup.sh 就能跑起来,简单直接。但 cron 有个老毛病——机器关机或重启时错过的任务,它不会补跑;任务跑没跑、跑成什么样,也只能靠自己往日志文件里写。systemd timer 就是为了解决这些问题而来的现代替代品,学会它只需要理解两个文件。
timer 管「什么时候跑」,service 管「跑什么」
systemd 把定时任务拆成两个单元文件。.service 文件描述要执行的命令,.timer 文件描述触发时间,两者同名、放在一起,timer 到点就拉起对应的 service。
先写 service 文件,例如每天凌晨两点做一次备份,/etc/systemd/system/backup.service:
[Unit]
Description=Daily backup job
[Service]
Type=oneshot
ExecStart=/usr/local/bin/backup.sh
Type=oneshot 表示这是一次性任务,命令跑完进程就退出,这是定时任务最常用的类型。注意 ExecStart 必须写绝对路径,systemd 不会像交互 shell 那样帮你解析 PATH 和 ~,脚本里用到的命令也最好写绝对路径,或者在 service 里用 Environment=PATH=... 显式声明。
再写 timer 文件,/etc/systemd/system/backup.timer:
[Unit]
Description=Run backup daily at 02:00
[Timer]
OnCalendar=*-*-* 02:00:00
Persistent=true
[Install]
WantedBy=timers.target
OnCalendar 的语法比 cron 直观:*-*-* 02:00:00 就是每天 02:00。想改成每小时一次写 OnCalendar=hourly,每周一凌晨三点写 OnCalendar=Mon *-*-* 03:00:00,都是一行搞定。Persistent=true 是关键:机器在预定时间关机或休眠,timer 会在下次开机后把错过的这次补跑回来——cron 永远做不到这一点。
启用与查看:三条命令就够
sudo systemctl daemon-reload
sudo systemctl enable --now backup.timer
systemctl list-timers --all
list-timers 会列出所有 timer 的下次触发时间(NEXT)和上次触发时间(LAST),一眼就能确认任务有没有按预期排上。想看某次任务到底跑成什么样,不用再翻自己写的日志文件:
systemctl status backup.service
journalctl -u backup.service --since "today"
任务的标准输出和标准错误默认都会进 journal,什么时候开始、什么时候结束、退出码是多少,全都按时间顺序记着。排障时这比 cron 的邮件通知或自写日志文件方便得多。
从 cron 迁移:先并行跑一周
已经有一堆 cron 任务在跑,不用一次性全迁。挑一个最不重要的任务,先用 timer 的写法跑起来,和 cron 版并行一周:list-timers 确认触发时间正常,journalctl 确认每次执行结果正常,再把 cron 里那行注释掉。迁移时最容易踩的坑有三个:
第一,环境变量。cron 任务的环境变量极少,systemd service 的环境更干净,连 HOME 都不一定是你以为的那个。脚本里不要依赖 ~、$USER 这类变量,路径一律写绝对路径。
第二,工作目录。ExecStart 的命令默认在根目录下执行,脚本里用相对路径读写文件会跑偏。在 service 里加一行 WorkingDirectory=/data/backup 就能定死工作目录。
第三,超时保护。cron 里一个卡住的任务能悄悄跑一整天,systemd 默认也有类似问题。可以在 service 里加 TimeoutStartSec=10min,超过十分钟还没跑完就直接杀掉并记一条失败日志,配合 OnFailure= 还能触发告警脚本。
什么时候还用 cron
timer 并不是要消灭 cron。临时加一条「今晚三点跑一次」的任务,crontab -e 加一行仍是最快的;容器里、极简系统上没有 systemd 的地方,cron 依然是唯一选择。判断标准很简单:任务需要补跑、需要可靠的执行记录、需要超时和失败处理时,用 timer;只是随手加一条一次性或临时性调度,cron 更顺手。
对个人服务器来说,一次性把备份、日志轮转、证书续期这几类长期任务迁到 timer 上,之后每次排障都能直接翻 journal,这份确定性值得花一个下午完成迁移。
- 点赞
- 收藏
- 关注作者
评论(0)