Linux 定时任务进阶:用 systemd timer 替代 cron 的实战做法

举报
yd_225891185 发表于 2026/11/07 06:20:17 2026/11/07
【摘要】 Linux 定时任务进阶:用 systemd timer 替代 cron 的实战做法用过 Linux 服务器的人,大多用 cron 写过定时任务:每天凌晨备份、每小时清理日志、每周重启一次服务。一行 0 2 * * * /path/backup.sh 就能跑起来,简单直接。但 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,这份确定性值得花一个下午完成迁移。

【声明】本内容来自华为云开发者社区博主,不代表华为云及华为云开发者社区的观点和立场。转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息,否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0)

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。