用 systemd timer 替代 cron 做定时任务的入门实践
每天凌晨两点半,你的服务器在做什么?对很多运维新手来说,答案往往是一条写在 crontab -e 里的定时任务。cron 简单好用,但当你需要更精细的控制、更清晰的日志和更可靠的失败重试时,它就显得有些力不从心了。今天这篇入门实践,就带你用 systemd timer 替代 cron,亲手做一个每天定时执行的备份任务。
一、为什么要用 systemd timer 替代 cron
cron 的优点是简单,一行就能定义一个任务。但它也有明显的短板。第一,cron 只知道按时间触发,任务执行失败了不会自动重试,也不会告诉你失败的原因,只能自己去翻邮件或者日志。第二,cron 的任务和系统启动过程是脱节的,如果机器在预定时间关机,错过的任务就永远错过了。第三,cron 的环境变量很少,脚本里经常要写绝对路径,否则就会出现手动能跑、定时跑不起来的怪现象。
systemd timer 则不一样。它是 systemd 的一部分,和服务管理共用同一套机制。任务本身就是一个 service,定时器只负责在合适的时间把它拉起来。这样做的好处是:执行结果可以用 systemctl status 查看,日志统一进 journalctl,失败可以配置自动重试,还能设置依赖关系和资源限制。
二、核心概念:两个文件组成一个定时任务
用 systemd timer 做定时任务,至少需要两个单元文件,放在 /etc/systemd/system/ 目录下。
第一个是 .service 文件,它定义要做什么。第二个是 .timer 文件,它定义什么时候做。两者用相同的文件名前缀配对,比如 backup.service 配 backup.timer。启动定时器后,systemd 会在到达时间点时自动启动对应的服务。
三、实操:每天凌晨做一次目录备份
假设我们要每天凌晨两点半,把 /data/website 备份到 /data/backup。先写服务文件。
[Unit]
Description=每天备份网站数据
After=network.target
[Service]
Type=oneshot
ExecStart=/usr/bin/rsync -av /data/website/ /data/backup/website/
注意这里的 Type=oneshot,表示这是一次性任务,执行完就退出,非常适合定时脚本。ExecStart 里要写命令的绝对路径,这是 systemd 的习惯,也是避免环境变量问题的好办法。
再写定时器文件,名字必须和服务文件对应。
[Unit]
Description=每天凌晨两点半触发备份
[Timer]
OnCalendar=*-*-* 02:30:00
Persistent=true
[Install]
WantedBy=timers.target
OnCalendar 是最常用的触发方式,写法和日历很像。Persistent=true 很重要,它的意思是:如果机器在两点半关机,开机后要把错过的这次任务补跑一次。这正是 cron 做不到的事。
四、启用、检查和查看日志
写好两个文件后,用下面几条命令把定时器跑起来:
systemctl daemon-reload
systemctl enable --now backup.timer
systemctl list-timers --all
systemctl status backup.timer
systemctl daemon-reload 是每次改完单元文件后都要做的第一步,不然 systemd 还不知道你改了什么。systemctl enable --now 表示同时设置开机自启并立即启动。systemctl list-timers --all 会列出所有定时器和下一次触发时间,这是检查配置是否生效最直观的办法。
想立刻验证一次,不要等到半夜。直接手动触发服务:
systemctl start backup.service
systemctl status backup.service
journalctl -u backup.service -n 50
journalctl -u backup.service -n 50 可以看到最近五十行日志,备份成功还是失败、复制了多少文件,在这里一目了然。比起 cron 要到处找日志,这种集中式日志要方便得多。
五、几个常用的时间写法
刚入门时,可以先记住这几种 OnCalendar 的写法。每天早上八点是 OnCalendar=*-*-* 08:00:00,每周一早上九点是 OnCalendar=Mon *-*-* 09:00:00,每月一号凌晨是 OnCalendar=*-*-01 00:00:00。如果想每十分钟跑一次,可以写 OnCalendar=*-*-* *:00/10:00。也可以用更简单的相对时间,比如开机十分钟后执行一次用 OnBootSec=10min,每隔一小时执行一次用 OnUnitActiveSec=1h。
六、新手最容易踩的四个坑
第一个坑是忘记 daemon-reload。改了文件不重新加载,systemd 用的还是旧配置,调试半天找不到原因。第二个坑是脚本里用了相对路径或者依赖 PATH。systemd 的环境很干净,命令和路径最好都写绝对路径,或者在脚本开头显式设置环境变量。第三个坑是 Type 选错了。一次性任务用 oneshot,长期运行的服务不要用它,否则 systemd 会以为任务已经结束。第四个坑是权限。备份目录的读写权限、脚本的可执行权限,都要在定时器启动前检查好,命令 chmod +x /usr/local/bin/backup.sh 和 ls -l /data/backup 都能帮你快速确认。
七、cron 和 systemd timer 怎么选
如果你只是在一台个人电脑上跑一条简单的提醒脚本,cron 足够了。但如果你在管理服务器,需要看日志、要重试、要补跑错过的任务,或者定时任务本身就是系统服务的一部分,systemd timer 是更合适的选择。很多现代发行版的系统任务,比如日志轮转和临时文件清理,内部已经在用 timer,学会它等于学会了系统本身的定时方式。
八、总结
用 systemd timer 替代 cron 并不复杂,记住三个步骤就可以上手:写一个 oneshot 类型的 .service,写一个配对的 .timer 并设置好 OnCalendar,再用 systemctl enable --now 启动它,并用 systemctl list-timers 和 journalctl 验证效果。今天的备份例子可以直接照搬,把目录和时间换成你自己的需求,就是你第一个真正可用的 systemd timer 任务。等你熟练之后,还可以试试加上失败重试、执行超时和邮件通知,让定时任务从能跑变成跑得稳。
- 点赞
- 收藏
- 关注作者
评论(0)