1.7.4 systemd定时器使用与对比

systemd 定时器(.timer)是基于 systemd 的计划任务机制,配合 .service 单元执行脚本或命令。适用于需要依赖关系、日志可观测、错过补偿和统一管理的任务。

原理草图(.timer 触发 .service)

文章图片

安装与环境确认
大多数发行版已内置 systemd。若使用最小化系统或容器镜像,请确认 systemd 存在。

# 查看 systemd 版本与状态
systemctl --version
systemctl is-system-running

# 若是 Debian/Ubuntu 精简环境缺失(示例)
apt-get update && apt-get install -y systemd

# RHEL/CentOS/Alma/Rocky 一般默认有 systemd(示例校验)
rpm -q systemd

完整示例:每日 02:00 备份任务
1) 准备脚本

# 备份脚本示例:/usr/local/bin/backup.sh
cat >/usr/local/bin/backup.sh <<'EOF'
#!/bin/bash
set -e
TS=$(date +%F_%H%M%S)
SRC="/etc"
DST="/var/backups/etc_$TS.tar.gz"
tar -zcf "$DST" "$SRC"
echo "backup ok: $DST"
EOF

chmod +x /usr/local/bin/backup.sh

2) 创建 service 单元

# /etc/systemd/system/backup.service
[Unit]
Description=Daily backup job
Wants=network-online.target
After=network-online.target

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

3) 创建 timer 单元

# /etc/systemd/system/backup.timer
[Unit]
Description=Timer for daily backup

[Timer]
OnCalendar=*-*-* 02:00:00
Persistent=true
RandomizedDelaySec=120

[Install]
WantedBy=timers.target

4) 启用与验证

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

# 查看定时器列表与下一次触发时间
systemctl list-timers --all | grep backup

# 查看执行日志
journalctl -u backup.service -n 50 --no-pager

关键参数与命令解释
- OnCalendar=:类似 cron 的日历表达式;示例 *-*-* 02:00:00 表示每天 02:00。
- OnBootSec=:系统启动后延迟触发;如 OnBootSec=10min
- OnUnitActiveSec=:以上次执行为基准的周期;如 OnUnitActiveSec=30min
- Persistent=true:关机期间错过的任务在下次开机后补偿执行。
- RandomizedDelaySec=:随机延迟执行,防止集群同时触发造成抖动。
- systemctl list-timers:查看所有定时器与下一次触发时间。
- journalctl -u xxx.service:查看对应任务日志。

与 cron 对比(简要结论)
- systemd:统一管理、日志集中、支持依赖与补偿、适合关键任务。
- cron:语法简单、遗留系统常用、需要自行处理日志与依赖。

常见排错清单

# 1) 定时器未触发:确认是否启用
systemctl is-enabled backup.timer
systemctl status backup.timer

# 2) 单元文件变更未生效
systemctl daemon-reload

# 3) 查看最近执行时间与下一次计划
systemctl list-timers --all | grep backup

# 4) 任务失败:查看详细日志
journalctl -u backup.service -e --no-pager

# 5) 检查脚本权限与路径
ls -l /usr/local/bin/backup.sh

练习
1) 将示例任务改为“每 30 分钟执行一次”,并添加 OnUnitActiveSec=30min
2) 增加 ConditionPathExists=/data,当目录存在时才执行备份。
3) 新建一个 cleanup.service + cleanup.timer,每天 03:30 删除 7 天前的备份文件,并验证日志输出。