用 systemd timer 替代 cron:让定时任务可查、可控、可告警
很多小服务上线时,定时任务随手就写进了 crontab:简单、熟悉、能跑。但等任务变多,问题也跟着来:上次到底跑没跑?跑失败了谁知道?日志散落在哪里?这时候,systemd timer 是一个值得考虑的替代方案,它不是更“高级”,而是更可观测。
先看结构。一个 timer 由两个单元组成:.service 定义“做什么”,.timer 定义“什么时候做”。比如每天凌晨清理过期缓存,可以写一个 cleanup.service,ExecStart 指向清理脚本,再配一个 cleanup.timer,写 OnCalendar=*-*-* 03:30:00,并加上 Persistent=true。这样即使机器在触发时间关机,开机后也会补跑一次,不会静悄悄漏掉。
可观测性是它最大的优势。systemctl list-timers 一眼能看到每个任务的下次触发、上次触发和对应的 service;systemctl status 能看到最近一次执行是否成功;journalctl -u cleanup.service 则集中保存了输出,不用再去翻某个没人记得的日志文件。任务失败时,还可以在 service 里加 OnFailure 指向一个告警单元,把失败事件推到现有的通知渠道,而不是等用户反馈才发现数据没更新。
迁移时有几个细节容易踩坑。第一,工作目录和环境变量:cron 里的环境很干净,systemd 同样如此,脚本依赖的路径、语言运行时和配置文件,最好在单元里用 WorkingDirectory 和 EnvironmentFile 显式写明,不要假设登录 shell 的环境。第二,时区:OnCalendar 按系统时区解释,服务器时区不是本地时区时,触发时间会差几个小时,写完先用 systemd-analyze calendar 校验表达式解析结果。第三,防止重入:同一个任务上一次还没跑完、下一次又触发时可能互相干扰,可以在 service 里加 flock 或用 Lock 文件,更新类任务尤其要注意。
当然,cron 并非一无是处:单机、一次性、写完就忘的小任务,crontab 仍然更快。判断标准很简单——这个任务失败了,我需不需要第一时间知道?需要,就值得把它交给 systemd timer 管理;不需要,就别为形式增加复杂度。把“能跑”升级成“跑没跑一眼能查”,是运维从经验走向工程化的一小步,但很实在。
- 点赞
- 收藏
- 关注作者
评论(0)