flock 是什么
定时任务最常见的生产事故是重入:上一次任务还没跑完,下一次触发又启动一个实例,两个进程同时操作同一份数据,结果互相覆盖或产生重复记录。flock 用文件锁解决这个问题:任务启动时先对锁文件加排他锁,拿不到锁说明上一个实例还在运行。加上 -n 表示非阻塞,立即失败退出,这是 cron 防叠加的标准做法;不加 -n 会一直等待,相当于把任务排队执行,通常不是想要的行为。
基本信息
| 适用平台 | Linux(util-linux 的 flock 命令;也可在脚本语言里调用同名系统调用) |
|---|---|
| 命令语法 | flock [-n] [-w 秒] 锁文件 命令 |
| 常用选项 | -n 非阻塞,拿不到锁立即退出 -w 等待指定秒数 -x 排他锁(默认) -s 共享锁 -o 运行前关闭锁描述符 |
| 所属 | util-linux |
| 锁文件位置 | /var/lock 或 /run/lock,属于 tmpfs,重启后自动清空 |
典型使用场景
- 防任务叠加:备份、同步、报表这类耗时任务,避免两次执行同时写同一份数据
- 防重复启动:脚本被 cron 与手工同时触发时,只允许一个实例运行
- 多机协调:多台机器通过共享存储上的同一锁文件做粗粒度互斥
- 保护资源:限制同一任务的并发数,避免打满磁盘 IO 或数据库连接
- 排障分析:用 fuser 或 lsof 查看当前是谁持有锁
两种用法
两种用法
# crontab 一行写法:拿不到锁直接跳过
*/5 * * * * /usr/bin/flock -n /var/lock/sync.lock /opt/scripts/sync.sh >> /var/log/sync.log 2>&1
#!/bin/bash
# 脚本内写法:用文件描述符 9 持锁,整段任务都在锁内
exec 9>/var/lock/backup.lock
flock -n 9 || { echo "another instance running, skip"; exit 0; }
# ... 任务主体 ...
fuser /var/lock/sync.lock # 查看当前持有锁的进程几种行为对照
| 用法 | 拿不到锁时的表现 | 适用场景 |
|---|---|---|
| flock -n | 立即退出,退出码非 0 | cron 防叠加,最常用 |
| flock -w 30 | 最多等 30 秒,超时后退出 | 希望任务短暂排队而不是直接跳过 |
| flock 不加选项 | 一直阻塞等待锁释放 | 交互式场景,cron 里会导致任务堆积 |
| flock -o | 先关闭锁文件描述符再执行命令 | 避免被调命令派生的子进程继续持有锁 |
flock 的互斥范围只是「同一个锁文件路径」。路径写得不一致(相对路径与绝对路径、软链接指向不同文件)就等于没加锁,脚本里一律使用固定的绝对路径。
进程被 kill -9 时内核会自动释放锁,但被中断留下的半成品数据需要脚本自己处理。防重入不能替代幂等设计,任务本身要能安全重跑。