迁移到 timer 是什么
把 crontab 迁移到 systemd timer 换来的是:日志自动进 journal、可以声明依赖顺序与资源限制、按日历时刻精确调度、关机错过的可以补跑。代价是每个任务要写两个单元文件:service 描述做什么,timer 描述什么时候做。迁移路径固定为五步:盘点任务、写 service、写 timer、并存验证、下线 cron,任何一步跳过都会留下重复执行或漏执行的隐患。
基本信息
| 场景 | 把现有 cron 任务迁移为 systemd timer |
|---|---|
| 产物 | xx.service 描述做什么,xx.timer 描述什么时候做 |
| 关键参数 | OnCalendar 定时刻、Persistent 补跑、RandomizedDelaySec 错峰 |
| 验证工具 | systemctl list-timers、journalctl -u、systemd-analyze calendar |
典型使用场景
- 需要日志与执行历史:journal 自动记录每次执行的输出与退出码
- 需要依赖顺序:After=mysql.service、Wants=network-online.target 保证前置条件
- 需要资源与优先级控制:Nice、IOSchedulingClass、MemoryMax 直接写在单元里
- 关机错过要补跑:Persistent=true 是 cron 不具备的能力
- 统一管理:任务定义以文件形式纳入配置管理与代码评审
service 单元
service 单元
# /etc/systemd/system/db-backup.service
[Unit]
Description=Daily DB backup
After=network-online.target mysql.service
Wants=network-online.target
[Service]
Type=oneshot
User=backup
ExecStart=/opt/scripts/db-backup.sh
Nice=10
IOSchedulingClass=idletimer 单元与启用
timer 单元与启用
# /etc/systemd/system/db-backup.timer
[Unit]
Description=Run db-backup daily
[Timer]
OnCalendar=*-*-* 02:30:00
Persistent=true
RandomizedDelaySec=300
[Install]
WantedBy=timers.target启用验证与下线 cron
启用验证与下线 cron
systemd-analyze calendar '*-*-* 02:30:00' # 先验证表达式解析出的下次触发时间
sudo systemctl daemon-reload
sudo systemctl enable --now db-backup.timer # enable 的是 timer,不是 service
systemctl list-timers db-backup.timer --no-pager
sudo systemctl start db-backup.service # 手动触发一次,不必等定时
journalctl -u db-backup.service --since today --no-pager | tail -n 20
crontab -l > ~/cron.bak && crontab -e # 验证通过后再删除旧 cron 行cron 与 timer 等价写法
| cron 写法 | timer 等价 | 说明 |
|---|---|---|
| 30 2 * * * | OnCalendar=*-*-* 02:30:00 | 日历表达式定时刻 |
| */10 * * * * | OnCalendar=*:0/10 | 每 10 分钟一次 |
| @reboot | OnBootSec=1min | 开机后触发 |
| 错过的执行 | Persistent=true | 只补最近一次 |
| 并发错峰 | RandomizedDelaySec= | 在时间点后加随机延迟 |
任务型脚本要用 Type=oneshot:默认 simple 会在 fork 后立即认为启动成功,systemctl 状态与实际执行结果脱节。
迁移前先盘点:crontab -l、/etc/crontab、/etc/cron.d、cron.{hourly,daily,weekly,monthly} 以及既有 timer 五处都要看,逐条记录后销账,避免只搬了用户任务表却漏掉系统目录里的任务。
迁移期两套并存会重复执行任务,可先把 cron 行改成 echo skipped 观察一天,确认 timer 正常后再删除。
迁移后日志进 journal,先确认 journald 持久化(/var/log/journal 目录存在),否则重启后执行历史全部丢失。
迁移检查清单
| 检查项 | 通过标准 | 说明 |
|---|---|---|
| 任务盘点完整 | 各处来源均有记录 | 避免只搬了一部分 |
| 表达式可解析 | 分析工具给出下次触发时间 | 启用前先验证 |
| 日志可追溯 | 服务有执行记录与退出码 | 确认日志留存已开启 |
| 旧任务已下线 | 任务表里不再重复 | 避免两套同时跑 |
| 资源限制已声明 | 单元里有对应字段 | 防止与业务争抢 |
迁移的价值不止是换个调度器:任务写成单元后可以声明依赖顺序、资源上限、失败策略与补跑规则,这些能力在任务表里都做不到;代价是定义变啰嗦,改一次要动两个文件,因此更适合长期运行、需要审计与可追溯的周期性作业。