Linux 任务调度:cron 与 systemd timer 对比

在 Linux 系统管理中,何时执行任务与执行什么同等重要。 最古老的工具是 cron,而在现代发行版中更常见的是 systemd timer。 本文将比较两者,并整理在不同场景下各自的适用性。


1. 为什么要比较 cron 与 systemd timer?



大多数 Linux 服务器都有类似需求:

  • 每天凌晨 3 点执行备份
  • 每 5 分钟运行一次健康检查脚本
  • 每周日压缩并清理日志
  • 启动后 1 分钟仅执行一次的初始化任务

传统上,这些都用 cron 处理,但如今许多发行版已将 systemd 作为默认 init 系统,systemd timer 成为强有力的替代方案。


2. cron 基本概念

2.1 cron 是什么?

cron 是一款老牌的 Unix/Linux 调度器。 它按预定时间/周期执行命令,配置主要通过 crontab 文件管理。

2.2 cron 配置位置

  • 系统级:/etc/crontab/etc/cron.d/
  • 用户级:通过 crontab -e 编辑 per‑user crontab

例如,每天凌晨 3 点执行备份脚本:

0 3 * * * /usr/local/bin/backup.sh

字段含义如下:

分  时  日  月  周  命令
0   3   *   *   *    /usr/local/bin/backup.sh

2.3 cron 的优点

  • 经过时间检验的成熟工具
  • 大多数 Unix/Linux 系统共通
  • 语法简洁,示例丰富
  • 在 systemd 之前的系统也可使用

2.4 cron 的局限

  • 与服务分离,难以追踪“与哪个服务相关”
  • 状态/日志查看不便(散落在 syslog、邮件等)
  • 依赖管理(如需先启动其他服务)弱
  • “启动后 5 分钟仅执行一次”这类相对时间调度不直观

3. systemd timer 基本概念



3.1 systemd timer 是什么?

systemd timer 是 systemd 的“计时器单元”。 它根据特定条件(时间、启动后经过时间等)触发另一个 systemd service

结构总是成对出现:

  • myjob.service → 定义实际要执行的任务
  • myjob.timer → 定义何时触发

3.2 service + timer 基本示例

以每天凌晨 3 点执行备份为例:

(1) 服务单元:/etc/systemd/system/backup.service

[Unit]
Description=Daily backup job

[Service]
Type=oneshot
ExecStart=/usr/local/bin/backup.sh

(2) 计时器单元:/etc/systemd/system/backup.timer

[Unit]
Description=Run daily backup at 3:00

[Timer]
OnCalendar=*-*-* 03:00:00
Persistent=true

[Install]
WantedBy=timers.target

激活:

sudo systemctl daemon-reload
sudo systemctl enable --now backup.timer

3.3 systemd timer 的优点

  • 与服务明确关联:结构清晰,易于定位
  • 日志管理方便journalctl -u backup.service 等查看日志
  • 灵活的触发条件
  • OnCalendar=:类似 cron 的时间表达式
  • OnBootSec=:启动后 X 秒
  • OnUnitActiveSec=OnUnitInactiveSec= 等:上一次执行后 X 秒
  • 依赖处理:可通过 After=Requires= 等表达
  • 与 systemd 生态深度集成:systemctl list-timerssystemctl status

3.4 systemd timer 的缺点

  • 学习曲线比 cron 稍陡(需编写两份文件)
  • 仅适用于 systemd 环境(旧系统或非 systemd 环境不支持)
  • 对于单行简单任务显得“过度”

4. cron 与 systemd timer 功能对比

4.1 大图对比表

项目 cron systemd timer
配置位置 /etc/crontabcrontab -e /etc/systemd/system/*.service/*.timer
目标 任意命令/脚本 systemd service
时间表达 cron 表达式(5 字段) OnCalendarOnBootSec 等多种选项
启动后 X 秒/分/时 限制,需额外脚本 OnBootSecOnStartupSec 直接支持
失败/重试 需自行实现 通过 service 单元配置部分可实现
日志查看 syslog、邮件等 journalctl -u <service>
依赖(网络/文件系统) 无内建支持 After=Requires=
与系统集成 高(systemd 全链路)
可移植性 较高 受 systemd 约束

5. 通过示例看差异

5.1 每天凌晨 3 点备份:cron vs timer

cron 版本

0 3 * * * /usr/local/bin/backup.sh

systemd timer 版本

# backup.service
[Unit]
Description=Daily backup job

[Service]
Type=oneshot
ExecStart=/usr/local/bin/backup.sh
# backup.timer
[Unit]
Description=Run daily backup at 3:00

[Timer]
OnCalendar=*-*-* 03:00:00
Persistent=true

[Install]
WantedBy=timers.target

5.2 启动后 5 分钟仅执行一次

cron 中通常需要 @reboot + sleeprc.local 等技巧。

systemd timer 实现

# init-job.service
[Unit]
Description=Run custom init job after boot

[Service]
Type=oneshot
ExecStart=/usr/local/bin/init-job.sh
# init-job.timer
[Unit]
Description=Run init job 5 minutes after boot

[Timer]
OnBootSec=5min
AccuracySec=1min

[Install]
WantedBy=timers.target

这样,启动后 5 分钟会触发 init-job.service


6. 该选哪一个?

6.1 继续使用 cron 的情况

  • 已有大量 cron 任务且不需要 systemd 集成
  • 服务器规模小,仅有几条简单定时任务
  • 需要兼容非 systemd 环境(如某些容器、BSD、极老系统)

6.2 选择 systemd timer 的情况

  • 系统已使用 systemd 管理大部分服务
  • 需要统一日志、状态查看
  • 需要相对时间调度(启动后 X 分钟、上一次执行后 Y 分钟)
  • 需要依赖管理(网络、数据库等)
  • 在 CI/CD、生产环境中追求一致的可观测性

7. 将现有 cron 迁移到 systemd timer 的技巧

  1. 列出当前 cron 任务 * crontab -l * 检查 /etc/crontab/etc/cron.d/*
  2. 拆分为 service + timer * “执行什么” → .service * “何时执行” → .timer
  3. 转换时间表达 * 0 3 * * *OnCalendar=*-*-* 03:00:00 * */5 * * * *OnCalendar=*:0/5
  4. 测试 * systemctl start myjob.service 手动验证 * systemctl start myjob.timersystemctl list-timers
  5. 停用旧 cron * 注释或删除旧条目,确认新计时器稳定后再移除

8. 结语:共存亦可

总结:

  • cron 仍是简单、可移植的调度器
  • systemd timer 在现代 Linux 环境中提供服务中心化、可观测性、灵活触发等优势

两者并无绝对“正确”答案。若已有 cron 任务无需迁移,保持即可;若正在编写新任务或与服务紧密耦合,优先考虑 systemd timer。

image