未来星球 未来星球
  • 首页
  • 新闻资讯
  • 技术教程
  • 软件工具
  • 知识百科
  • 生活实用
  • 个人随笔
  • 生命外星人
首页 › 技术教程 › 用 systemd 定时器替代 cron:3 份配置,4 个必踩的坑
  • 0
  • 0

用 systemd 定时器替代 cron:3 份配置,4 个必踩的坑

admin
1 天前
8 views
用 systemd 定时器替代 cron:3 份配置,4 个必踩的坑-未来星球

一台跑了两年的备份机,cron 里躺着七条任务。某天磁盘满了,备份连续失败了十九天,没人发现——因为 cron 把错误写进了系统邮件,而这台机器根本没装邮件服务。

cron 最大的问题不是不能定时,是它不告诉你它没做。任务成没成功、跑了多久、上次是什么时候跑的,全靠自己另建一套监控。

下面是把它换成 systemd timer 的完整过程,环境是 Debian 12(systemd 252)和 Ubuntu 22.04(systemd 249),两台上都跑通过。三个文件,一处软链接,四行命令,之后所有执行记录都进 journal。

1. 先看清楚两者差在哪

cron 是一个「到点就 fork 一个 shell」的调度器,它对任务本身一无所知。systemd timer 则是把「什么时候跑」和「跑什么」拆成两个单元,跑的东西是一个正经的 service。拆开之后,日志、超时、依赖、失败重试全部由 systemd 接管。

能力 cron systemd timer
执行日志 默认发系统邮件,通常没人收 直接进 journal,journalctl -u 可查
关机期间错过的任务 直接丢掉 Persistent=true 开机补跑一次
超时控制 无,卡死就永久卡死 TimeoutStartSec 到点强杀
错开并发 手动改时间 RandomizedDelaySec 自动抖动
依赖顺序 只能靠 sleep 猜 After= / Requires= 明确声明
环境变量 一份极简的 PATH,和登录 shell 不同 Environment= 显式声明

表格里最值钱的一行是「关机期间错过的任务」。备份机半夜断电、白天修好,cron 那一晚的备份就是永久缺失,而且不会有任何提示。

2. 目录树:三个文件放哪里

系统级单元放 /etc/systemd/system/,脚本放 /usr/local/bin/。不要把脚本和单元混在同一个目录里,升级系统时容易一起被覆盖。

/etc/systemd/system/
├── pg-backup.service      # 干什么
├── pg-backup.timer        # 什么时候干
└── timers.target.wants/
    └── pg-backup.timer -> ../pg-backup.timer   # 开机启用

/usr/local/bin/
└── pg-backup.sh           # 实际执行的脚本

注意那个 timers.target.wants 目录里的软链接。它不是必须手建的,用 systemctl enable 会自动生成,把它列出来是为了让你知道 enable 到底改了什么——很多人以为 enable 是改配置文件,其实只是建一个链接。

3. 第一份配置:service,定义「跑什么」

定时任务的服务类型必须是 Type=oneshot,因为它跑完就退出,不常驻。写成 Type=simple 会让 systemd 一直以为它还在启动中,后续的超时判断全都失效。

[Unit]
Description=PostgreSQL daily dump to /srv/backup
After=network-online.target postgresql.service
Wants=network-online.target

[Service]
Type=oneshot
User=backup
Group=backup
Environment=PGPASSFILE=/home/backup/.pgpass
Environment=BACKUP_DIR=/srv/backup/pg
ExecStart=/usr/local/bin/pg-backup.sh
Nice=10
IOSchedulingClass=idle
TimeoutStartSec=1800
Restart=on-failure
RestartSec=300

[Install]
WantedBy=multi-user.target

Restart=on-failure 配合 oneshot 是允许的,但它只在本次启动内重试,重试次数用完就放弃,不会等到下一个周期。真要「失败就等到明天再试」,应该靠 timer 的 OnFailure= 去拉起一个通知单元。

脚本本身要做三件事:先检查目标目录的可用空间,再执行导出,最后删掉超过保留期的旧文件。空间检查放在导出之前,是因为磁盘满的时候导出会写一个半截文件,比不导出更危险。

#!/bin/bash
set -euo pipefail

: "${BACKUP_DIR:?BACKUP_DIR is not set}"
KEEP_DAYS=14
printf -v STAMP '%(%Y%m%d-%H%M)T' -1

mkdir -p "$BACKUP_DIR"

# 剩余空间低于 2GB 时 awk 以非零码退出,pipefail 会让整个脚本停下
df -Pk "$BACKUP_DIR" | awk 'NR==2 && $4 < 2097152 {print "abort: less than 2GB free"; exit 1}'

pg_dumpall --clean --if-exists | gzip > "$BACKUP_DIR/all-$STAMP.sql.gz"

find "$BACKUP_DIR" -maxdepth 1 -name 'all-*.sql.gz' -mtime +"$KEEP_DAYS" -exec rm -f {} +
echo "done: all-$STAMP.sql.gz"

4. 第二份配置:timer,定义「什么时候」

[Unit]
Description=Run pg-backup daily at 03:30
Requires=pg-backup.service

[Timer]
Unit=pg-backup.service
OnCalendar=*-*-* 03:30:00
Persistent=true
RandomizedDelaySec=600
AccuracySec=1min

[Install]
WantedBy=timers.target

OnCalendar=*-*-* 03:30:00 的含义是「每年每月每日的 03:30:00」,等价的旧写法是 03:30。写成 03:30 更短,但容易和「每 30 小时」的间隔语法混淆,建议一律写全。

RandomizedDelaySec=600 让实际触发时间在 03:30 之后十分钟内随机浮动。如果你的机器不止一台,这个参数是必须的:十台机器同时向同一个对象存储上传,比单台失败更难查。

5. 启用与验收:四条命令

  1. sudo systemctl daemon-reload —— 改完单元文件必须执行,否则 systemd 用的还是旧内容。
  2. sudo systemctl enable --now pg-backup.timer —— 建软链接并立刻启动计时器。
  3. systemctl list-timers pg-backup.timer —— 看 NEXT 和 LAST 两列,NEXT 有值就说明排上了。
  4. sudo systemctl start pg-backup.service 然后 journalctl -u pg-backup -n 50 —— 不等定时,先手动跑一次,确认脚本本身没问题。

验收的标准不是「NEXT 有值」,而是手动触发一次之后,journal 里有完整的输出,退出状态是 0,目标目录多了一个当天日期的文件。这三条缺任何一条,都别急着等第二天。

6. 四个必然踩到的坑

下面四条是我在两台机器上挨个踩过的,按出现概率排序。它们都不会报错,只会让任务安静地不执行——这比报错难受得多。

坑一:ExecStart 不经过 shell,管道和重定向全部失效。写成 ExecStart=/bin/echo a | gzip > /tmp/x,systemd 会试图执行一个叫 | 的程序。要保留 shell 语义,必须显式写出解释器:ExecStart=/bin/bash -lc '/usr/local/bin/pg-backup.sh'。单引号里的内容由 bash 解析,systemd 只负责把整串交给它。

坑二:Persistent=true 的补跑会和 RandomizedDelaySec 叠加。机器凌晨两点关机、早上九点开机,补跑不会在 03:30 发生,而是在开机后叠加一个随机延迟。如果你有一个「必须在北京时间六点前完成」的下游任务,这个组合会让它偶尔失败,且没有任何日志提示原因。

坑三:OnCalendar 用的是系统时区,容器里通常是 UTC。在 Docker 或 LXC 里配 03:30,宿主机看着是 11:30 才跑。timedatectl 一眼能看出时区,但很多人是在排查了半小时之后才想起来看。跨时区部署时,直接在 timer 里写 OnCalendar=*-*-* 03:30:00 Asia/Shanghai,systemd 249 以上支持在表达式里指定时区。

坑四:用户级 timer 需要 linger,否则用户一登出就停。把单元放在 ~/.config/systemd/user/ 下、用 systemctl --user enable 启用,看起来一切正常,但 SSH 会话一断,计时器就跟着会话消失。执行 loginctl enable-linger backup 才能让它在没有登录会话时继续运行。

7. 迁完之后,cron 什么时候还该留着

不是所有 cron 任务都值得搬。一次性、临时性的任务留在 cron 里更省事:写一行 crontab -e 就完事,不必建两个文件。

值得搬的是三类:需要知道成功与否的、错过一次就有后果的、以及需要和别的服务排先后顺序的。判断标准很简单:这个任务失败了,你会不会想知道。会,就搬。

有一个前提要先确认:journal 默认可能不持久化。如果 /var/log/journal 目录不存在,systemd 会把日志只写在内存里,机器一重启就全没了。你要查的是「上周三那次为什么失败」,而这个问题的答案可能已经被一次重启抹掉。

处理方式很简单:sudo mkdir -p /var/log/journal,然后 sudo systemctl restart systemd-journald。之后 journalctl --disk-usage 能看到实际占用,默认上限是磁盘的百分之十。这一步不做,前面所有「可查询」的说法都是空话。

搬完之后,cron 里那七条任务可以逐条注释掉,留一周观察期。观察期内两边都留着会跑两遍,所以更稳的做法是先把 cron 那条改成 # 开头,只留 timer,一周后确认 journal 里有七天的成功记录,再把整行删掉。

写在最后

这套东西真正的价值不在「更现代」,而在它把「任务有没有做」变成了一个可以查询的事实,而不是一个需要相信的假设。cron 的运行状态是一种信念,systemd 的运行状态是一条记录。

十九天没人发现备份失败,问题从来不在调度器。是那台机器上,没有任何一个地方能回答「上次成功是什么时候」这个问题。换工具解决不了没人看的问题,但至少让「看」这件事变得只要一条命令。

后来我给那台机器加了一条更土的规则:备份目录里如果最新的文件名不是今天,就在 SSH 登录时打一行提示。它比任何监控系统都更早发现问题。能被顺手看见的告警,才是有效的告警。


你机器上那几条 cron,最近一次成功是什么时候?现在能查到吗?

0

飞机舷窗为什么是圆角:1954年两次解体,和一枚方形窗角

上一篇

局域网传一个 2GB 的文件:4 个工具的边界,和 3 种选错的信号

下一篇

评论 (0)

登录后可发布~
立即登录
暂无评论

admin

当生活给你的全是不如意,那你一定要相信自己的兴趣!
209
文章
0
评论
-11
喜欢
2026 年 11 月
一 二 三 四 五 六 日
 1
2345678
9101112131415
16171819202122
23242526272829
30  
« 10 月    

近期评论

聚合文章

当 AI 开始改作文:三代人的代价,和一个不太好接受的推论
K2-18b 的 3.4σ:124 光年外,和三年没排掉的质疑
配一把钥匙,用了 40 分钟,和 3 次试插
AI新闻日报–2026年11月8日:46场公投,和110亿美元
冰箱冷藏室总积水:7 项措施,按投入产出排的一份清单
处理一份 PDF:4 个工具的适用边界,和 3 种选错的信号
用 restic 做异地加密备份:6 份配置,和 4 个必然踩到的坑
牛奶盒为什么是方的,可乐瓶是圆的:1915年,和一道装车算术

猜你喜欢

2026年AI工具实战指南:7个免费工具让你效率翻倍

2026年AI工具实战指南:7个免费工具让你效率翻倍

admin
91 0 0
Python 自动化办公:每天省2小时,从这些脚本开始

Python 自动化办公:每天省2小时,从这些脚本开始

admin
88 0 0
2026 年必学的 5 个 AI 提示词技巧

2026 年必学的 5 个 AI 提示词技巧

admin
104 0 0
用WireGuard打一条两机房内网:3份配置,和4个必然踩到的坑

用WireGuard打一条两机房内网:3份配置,和4个必然踩到的坑

admin
16 0 0

关于我们

你是否对浩瀚的宇宙充满好奇?你是否渴望掌握未来科技的力量?现在,机会来了!“未来星球”将带你进入奇妙世界,开启你的科技探险之旅! 这是一个充满想象和创造力的博客!

分类导航

首页 新闻资讯 技术教程 软件工具 知识百科 生活实用 个人随笔 生命外星人

友情链接

未来星球AI工具【网络版】 未来星球 pycharm官方站【中国】
Copyright © 2026 未来星球. Designed by nicetheme. 蒙ICP备2026002569号-1
  • 请到 [后台->外观->菜单] 中设置菜单
  • AI未来
  • 生活百科
  • 档案
  • 外星人
  • 未来星球

admin

当生活给你的全是不如意,那你一定要相信自己的兴趣!
209
文章
0
评论
-11
喜欢