systemd 定时器实战:用 Timer Unit 取代 Cron 的现代任务编排 原创
为什么用 systemd 定时器取代 Cron
在传统 Linux 服务器上,周期性任务通常交给 Cron(crontab)处理。但 Cron 存在几个先天短板:任务输出默认丢失、依赖单独的守护进程、无法感知服务状态、重启后无法自动恢复。systemd 自 197 版本起提供了原生定时器(timer unit),把定时任务和服务管理统一到同一套体系中,日志、依赖、资源限制、失败重试全部内置,是当代运维的首选方案。
本文从 timer unit 的基本结构讲起,逐步演示如何用 systemd 定时器编排真实的服务器任务,并给出生产环境的最佳实践。
Timer Unit 的核心概念
一个定时任务由两个文件组成:
- 服务单元(
xxx.service):定义要执行的具体任务。 - 定时器单元(
xxx.timer):定义何时触发该服务。
定时器有两种触发模式:
| 模式 | 关键字 | 说明 |
|---|---|---|
| 单调时间 | OnBootSec / OnActiveSec |
自启动或上次触发后经过固定时长 |
| 日历时间 | OnCalendar |
按日期时间规则(类似 cron 表达式)触发 |
创建第一个定时任务
假设我们要每天凌晨 3 点备份数据库。先创建服务单元:
# /etc/systemd/system/backup.service
[Unit]
Description=Daily database backup
[Service]
Type=oneshot
ExecStart=/usr/local/bin/backup.sh
再创建对应的定时器单元:
# /etc/systemd/system/backup.timer
[Unit]
Description=Run backup daily at 03:00
[Timer]
OnCalendar=*-*-* 03:00:00
Persistent=true
[Install]
WantedBy=timers.target
启用并启动:
systemctl daemon-reload
systemctl enable --now backup.timer
日历表达式的写法
systemd 的 OnCalendar 语法比 cron 更灵活,支持自然语言与通配符:
| 需求 | 表达式 |
|---|---|
| 每天 03:00 | *-*-* 03:00:00 |
| 每周一 08:30 | Mon *-*-* 08:30:00 |
| 每月 1 号 | *-*-01 00:00:00 |
| 每 30 分钟 | *-*-* *:00/30:00 |
| 开机后 5 分钟 | OnBootSec=5min |
用 systemd-analyze calendar '表达式' 可校验表达式并预览下一次触发时间。
Persistent 与精确控制
Persistent=true 是关键选项:当服务器在计划触发时刻处于关机状态时,启动后会补跑错过的任务。这对备份、同步类任务至关重要,避免漏执行。若需要严格控制两次触发之间不重叠,可配合 OnActiveSec 和 Unit= 指定目标服务。
[Timer]
Unit=backup.service
OnCalendar=*-*-* 03:00:00
Persistent=true
RandomizedDelaySec=60
RandomizedDelaySec 可打散触发时刻,避免多台机器在同一秒发起任务造成突刺。
任务输出与失败处理
与 cron 默认丢弃输出不同,systemd 定时任务的所有 stdout/stderr 都会进入 journal,可用 journalctl -u backup.service 查看。配合 ExecStart 与失败重试:
[Service]
Type=oneshot
ExecStart=/usr/local/bin/backup.sh
# 失败后最多重试 3 次,间隔 5 分钟
Restart=on-failure
RestartSec=5min
StartLimitBurst=3
管理命令速查
systemctl list-timers # 列出所有定时器及下次触发时间
systemctl status backup.timer # 查看定时器状态
systemctl start backup.service # 立即手动执行一次任务
systemctl list-timer-units
总结
systemd 定时器把”什么时候跑”和”跑什么”拆成 timer 与 service 两个单元,天然继承了日志、依赖、资源限制和失败恢复能力。对需要可靠执行、错峰调度、错过补跑的服务器任务,建议优先使用 Timer Unit 而非传统 Cron。