Linux 定时任务进阶:用 systemd timer 替代 cron 的完整实践
为什么还要讨论定时任务
大多数 Linux 服务器上的定时任务仍然写在 crontab 里。cron 简单直接,语法几分钟就能学会,但它有一个长期被忽视的短板:可观测性有限。任务到底有没有执行、执行了多久、失败原因是什么,往往要靠脚本自己写日志;机器在计划时间处于关机状态时,错过的任务也不会自动补跑。
timer 其实是一对文件
systemd timer 不是单个配置文件,而是一对单元:.service 负责描述“做什么”,.timer 负责描述“什么时候做”。两者分离之后,同一个任务既可以由定时器触发,也可以手动执行,排障时非常方便。
一个最小可用的例子
# /etc/systemd/system/backup.service
[Unit]
Description=Daily backup job
[Service]
Type=oneshot
ExecStart=/usr/local/bin/backup.sh
# /etc/systemd/system/backup.timer
[Unit]
Description=Run backup every day at 02:30
[Timer]
OnCalendar=*-*-* 02:30:00
Persistent=true
RandomizedDelaySec=300
[Install]
WantedBy=timers.target
启用只需要两条命令:systemctl daemon-reload 和 systemctl enable --now backup.timer。之后用 systemctl list-timers 就能看到所有定时器的下次触发时间。
三个值得关注的字段
OnCalendar 采用类似日历的语法,比 cron 的五段式更直观,也支持 hourly、daily 这类简写。
Persistent=true 解决的是错失补偿:如果计划时间点机器是关机的,下次开机后会立即补跑一次。对备份、报表这类“漏一次就麻烦”的任务,这个开关比 cron 省心得多。
RandomizedDelaySec 用来打散触发时间。当几十台机器配置了同样的定时任务时,它能把唤醒时间随机错开,避免同一秒集中冲击共享存储或后端接口。默认的 AccuracySec 是一分钟,如果对精度要求更高可以调小。
日志与排障
timer 每次触发都会在 journal 中留下独立记录,journalctl -u backup.service --since today 可以直接看到本次执行的输出和退出码,不需要再自己维护日志轮转。配合 systemctl status backup.timer,还能确认下次触发时间和最近一次运行结果。
并发与超时
服务类型设为 Type=oneshot 时,如果上一次还没结束,新的触发默认会等待。可以用 TimeoutStartSec 限制单次运行的最长时间,必要时再用互斥配置控制并发,避免备份进程叠跑把磁盘打满。这一步在 crontab 时代通常只能靠脚本里的文件锁自行实现。
迁移时的几点建议
并不是所有 crontab 都值得迁移。短小、无状态、失败也无所谓的脚本继续留在 cron 里更省事;而需要审计、需要错失补跑、需要和 systemd 依赖关系协同的任务,迁到 timer 收益明显。迁移时先在测试机用 systemctl start backup.service 手动跑通,再启用 timer,避免开机后才发现路径或环境变量不一致。
小结
cron 解决的是“有没有定时”,systemd timer 进一步解决“定时是否可靠、可观测、可控”。把关键任务从 crontab 迁到 timer,是一次低成本、高回报的运维改造。
- 点赞
- 收藏
- 关注作者
评论(0)