别再只用 cron 了:systemd timer 定时任务入门与排障
很多 Linux 服务器上的定时任务都是用 cron 写的,简单是简单,但一旦任务没跑,你往往只能对着空日志发呆:它到底跑没跑、跑了多久、为什么失败,cron 都不告诉你。systemd timer 是现代发行版自带的替代方案,把定时任务当成系统服务来管,日志、状态、失败重试一应俱全,值得花十分钟学会。
第一步:理解两个文件的关系
systemd timer 由一对文件组成:一个 .service 文件定义要做什么,一个 .timer 文件定义什么时候做。比如每天凌晨三点清理一次临时文件,先写服务文件 /etc/systemd/system/cleanup.service:
[Unit]
Description=清理临时文件
[Service]
Type=oneshot
ExecStart=/usr/bin/find /tmp -type f -atime +7 -delete
再写定时器文件 /etc/systemd/system/cleanup.timer:
[Unit]
Description=每天清理临时文件
[Timer]
OnCalendar=*-*-* 03:00:00
Persistent=true
[Install]
WantedBy=timers.target
OnCalendar 的写法很直观,星号代表每天;Persistent=true 的意思是如果机器在三点关机了,开机后会补跑一次,这是 cron 做不到的。
第二步:启用并验证
写好文件后依次执行:
systemctl daemon-reload
systemctl enable --now cleanup.timer
systemctl list-timers --all | grep cleanup
list-timers 会直接告诉你下一次触发时间,比 cron 的猜谜式排障舒服得多。想立刻手动跑一次验证逻辑是否正确,不用等到凌晨三点,直接 systemctl start cleanup.service,再用 journalctl -u cleanup.service 看日志,输出、报错都在这里,一条命令全齐。
进阶:更灵活的时间写法
OnCalendar 不止能写每天固定时刻。工作日早上九点跑巡检可以写成 Mon..Fri 09:00:00,每小时整点跑一次写成 hourly,每月一号写成 monthly。如果服务器很多台都在同一时刻跑任务,还可以在 timer 里加 RandomizedDelaySec=10min,让各台机器在三点到三点十分之间随机错峰,避免同时打爆数据库。需要开机后延迟触发的场景则用 OnBootSec=15min 这类单调定时器,机器启动十五分钟后再跑,适合那些依赖网络和其它服务就绪的任务。
还要注意一个精度细节:默认情况下定时器的触发精度是一分钟,系统会把触发时间凑整以省电。如果你的任务对时间敏感,比如必须在整点前后几秒内执行,可以在 timer 文件里写 AccuracySec=1s,把精度收紧到一秒,当然代价是系统唤醒更频繁,一般任务没必要这么做。
第三步:常见坑与排障
第一,时间没生效:改了 timer 文件必须先 daemon-reload 再 restart 定时器,否则跑的还是旧时间。第二,环境变量缺失:systemd 服务默认环境非常干净,PATH 里可能没有你习惯的命令,ExecStart 尽量写绝对路径,必要时在 service 文件里用 Environment 显式声明。第三,任务超时被杀:默认服务没有运行时间限制问题不大,但如果清理脚本卡住,配合 TimeoutStartSec 设置一个上限,避免它无限挂起。
最后提醒一句:从 cron 迁移不必一次性全搬,先挑一个最重要又最常出问题的任务改成 timer,跑一周确认日志和触发时间都正常,再逐步迁移其余任务。迁移前先用 crontab -l 把现有任务完整导出来逐条对照,避免漏迁;迁移后保留旧 cron 注释一周,确认新定时器稳定后再删除。定时任务的价值不在写得多巧妙,而在出问题时你能不能第一时间知道、第一时间定位,systemd timer 在这一点上比 cron 强得多。
- 点赞
- 收藏
- 关注作者
评论(0)