systemd 定时任务互斥:用 flock 把重复执行挡住

举报
yd_269248920 发表于 2026/11/07 00:37:16 2026/11/07
【摘要】 单机定时任务重复执行的三种典型成因,以及 flock + oneshot + 时区三件套怎么配、怎么验证锁真的生效。

一、问题:定时任务为什么会重复跑

把每日巡检脚本挂到 systemd timer 上之后,最先遇到的问题不是脚本写错,而是它偶尔会被启动两次。典型场景有三种:

  • 上一次运行还没结束,定时器的下一次触发已经到点;
  • 运维手动 systemctl start 一次做验证,正好撞上自动触发;
  • 脚本内部用 nohup 或 & 把耗时步骤丢到后台,systemd 认为主进程已退出,于是又拉起新实例。

后果往往比“多占一点 CPU”严重得多:重复上报监控数据会让告警风暴翻倍;重复提交工单、重复扣减额度、重复写审计日志,都需要人工回头清理。因此「同一个任务在同一时刻只能有一个实例在跑」应当被当作硬约束,而不是靠脚本自觉。

二、一个 flock 就够,不必引入队列

很多人第一反应是上 Redis 分布式锁或者消息队列。对于单机定时任务,这是过度设计。Linux 自带的 flock 是内核级的建议锁,进程退出(包括被 kill -9)时由内核自动释放,不存在“锁残留导致任务永久挂起”的经典事故。

最小改动是在脚本开头加三行:

#!/usr/bin/env bash
set -euo pipefail
exec 9>/var/lock/backup.lock
flock -n 9 || { echo "already running, skip"; exit 0; }

关键点有两个:一是 exec 9> 必须在 flock 之前,锁的持有者是这个文件描述符而不是某条命令;二是 -n(non-blocking)配合 exit 0,让后来的实例安静退出,不要排队等待——定时任务排队会不断积压,等到半夜一起跑完,反而把 IO 打满。

三、systemd 侧的三个配套开关

只加 flock 还不够,unit 文件里有三处需要同时设对:

[Service]
Type=oneshot
ExecStart=/opt/scripts/backup.sh
TimeoutStartSec=3600
Restart=no

[Timer]
OnCalendar=*-*-* 03:30:00
Persistent=true
AccuracySec=1min
  • Type=oneshot:让 systemd 等到进程真正退出才认为结束。用默认的 simple 时,systemd 在 fork 后立刻认为启动成功,systemctl status 也看不出它还在跑。
  • OnCalendar 与时区:服务器常是 UTC,而业务期望是本地时间。timedatectl 显示的是系统时区,若 timedatectl show -p Timezone 返回 UTC,请写 03:30 UTC 或在 unit 里加 Environment=TZ=Asia/Shanghai,否则任务会在本地时间的错位小时跑。
  • Persistent=true:机器关机错过了触发点,开机会补跑一次。这对「每天必须有一份快照」的场景是必要的,但对「每小时上报一次心跳」则不合适,会一次性补出几十次,需要靠 flock 与脚本内的时间窗判断兜住。

四、验证是否真的互斥

很多同学加完 flock 就结束了,没验证。可靠的做法是人工制造并发:动手写一个测试脚本,前 20 秒不停打时间戳,同时在两个终端里各起一次,观察第二个是否立即返回 already running, skip。

# 终端 A
./backup.sh
# 终端 B(1 秒后)
./backup.sh   # 应立刻打印 already running 并返回 0

再用 flock -n /var/lock/backup.lock -c 'echo locked' 反向确认锁确实被持有。lsof /var/lock/backup.lock 应当显示 PID 而非空。

另一个容易漏的点:如果脚本用 bash script.sh & 启动子任务却不 wait,主脚本退出后锁随之释放,子任务仍在跑——此时互斥形同虚设。要么在主脚本结尾 wait,要么把子任务也放进同一个进程组统一回收。

五、结论

单机定时任务的互斥问题,不需要引入任何外部组件:内核 flock + oneshot + 正确的时区配置,三件事加起来不到二十行。真正花时间的往往不是写锁,而是验证锁生效了——构造一次人工并发,比读十遍文档可靠。

把这套约束固定下来之后,定时任务从「偶尔重跑一次,人工去清理数据」变成「跑多少天都不用管」,这才是自动化该有的形态。

【声明】本内容来自华为云开发者社区博主,不代表华为云及华为云开发者社区的观点和立场。转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息,否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0)

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。