flock 是什么
flock 利用内核的 flock 系统调用对文件加锁,用来保证同一时刻只有一个实例在跑。它的典型用法是包住一条命令:拿不到锁就退出或等待。锁由内核维护、不写进文件内容,进程退出或崩溃时锁自动释放,所以不会出现「陈旧的死锁文件」导致任务永远跑不起来。
基本信息
| 适用平台 | Linux/Unix(util-linux 提供命令,脚本里也可用 flock 系统调用) |
|---|---|
| 命令语法 | flock [选项] 锁文件 命令 / flock [选项] 数字fd |
| 常用选项 | -n 拿不到锁立即失败 -w 秒数 限时等待 -c 以字符串形式给命令 -s 共享锁 -x 独占锁(默认) |
| 默认行为 | 不加 -n 或 -w 时会一直排队等待,这在 cron 场景会造成进程堆积 |
| 退出码 | 拿不到锁时返回非零(默认 1,可用 -E 指定) |
典型使用场景
- 防定时任务重叠:上一次还没跑完,这次直接跳过
- 脚本重入保护:手动执行时避免与定时任务撞车
- 串行化资源访问:多实例共享同一份数据时保证顺序
- 批量运维节流:确保同类操作不会并发压垮目标
- 发布流程加锁:避免两次发布同时进行
常用示例
常用示例
flock -n /var/lock/backup.lock -c '/usr/local/bin/backup.sh' # 拿不到锁立刻退出
flock -w 30 /var/lock/sync.lock /usr/local/bin/sync.sh # 最多等 30 秒
# cron 防重叠的标准写法
*/10 * * * * /usr/bin/flock -n /var/lock/report.lock /usr/local/bin/report.sh
# 脚本内分段持锁(fd 形式)
exec 9>/var/lock/app.lock
flock -n 9 || { echo '已有实例在跑'; exit 1; }
# 后续业务逻辑……
exec 9>&- # 释放常用选项读法
| 选项 | 作用 | 注意 |
|---|---|---|
| -n | 非阻塞,拿不到锁立即失败 | cron 与自动化场景必加 |
| -w 秒 | 限时等待,超时失败 | 介于等待与立即失败之间的折中 |
| -c 字符串 | 把命令作为字符串传入 | 注意引号嵌套 |
| -s 与 -x | 共享锁与独占锁 | 默认独占,读多写少场景可用共享锁 |
| 数字 fd | 在脚本内对已打开的文件描述符加锁 | 适合分段持锁 |
| -E 数字 | 自定义冲突时的退出码 | 便于上层判断是「已有实例」还是别的问题 |
锁由内核的 flock 调用维护,不写进文件内容:进程正常退出、被 kill 或崩溃,锁都会随文件描述符关闭而释放。所以「锁文件还在磁盘上」并不代表任务还在跑,判断是否在运行要看进程而不是看文件。
跨主机互斥不要依赖 flock:NFS 上的锁语义受挂载选项与版本影响,行为可能与本地不同。需要跨主机串行时,用数据库行锁、分布式锁服务或带幂等的任务调度来保证。