最直接有效的方式是用 flock 命令加锁,它由内核保证原子性,进程退出自动释放锁,无需手动清理,也避免了 PID 文件残留或文件竞态问题。

最直接有效的方式是用 flock 命令加锁,它由内核保证原子性,进程退出自动释放锁,无需手动清理,也避免了 PID 文件残留或文件竞态问题。
flock 外部加锁(推荐用于 crontab)
不改脚本本身,只在调度层加锁,适合绝大多数定时任务场景:
- 把原 crontab 行:
* */2 * * * /usr/bin/python3 /opt/task.py - 改成:
* */2 * * * /usr/bin/flock -xn /tmp/task.lock -c "/usr/bin/python3 /opt/task.py" -
-x表示独占锁,-n表示拿不到锁立刻退出(不等待),/tmp/task.lock是锁文件路径,建议用绝对路径 - 注意命令部分必须用双引号包裹,否则 shell 解析会出错
flock 内部加锁(脚本内嵌方式)
适合无法修改 crontab、或需精细控制生命周期的场景:
Linux 安全审计工具,检查 SSH 配置、开放/监听端口、防火墙规则(ufw/iptables/nftables)、失败登录尝试、sudoers 权限...
- 在脚本开头用子 shell 封装逻辑,并绑定文件描述符:
#!/bin/bashexec 200>/tmp/my_script.lockflock -n 200 || { echo "Another instance is running"; exit 1; }# 正常业务逻辑放这里echo "Running..."sleep 10- 子 shell 结束或进程退出时,fd 200 自动关闭,锁自动释放
替代方案:mkdir 原子锁(轻量无依赖)
当系统没有 flock 或需跨平台兼容时,可用目录创建实现可靠互斥:
- 利用
mkdir的原子性:成功则获得锁,失败说明已被占用 LOCK_DIR="/tmp/my_script.lock.d"if ! mkdir "$LOCK_DIR" 2>/dev/null; then echo "Locked, exiting"; exit 1; fi- 结尾加
rm -rf "$LOCK_DIR",并配合trap 'rm -rf $LOCK_DIR' EXIT确保异常退出也能清理
多机/容器环境必须用 Redis 分布式锁
单机锁(flock、PID、mkdir)在 Docker 多副本、K8s 多 Pod 下完全失效:
- 锁 key 应含时间维度,如
task:sync:20260729,避免跨天冲突 - value 必须唯一标识本次执行,例如
"$(hostname)-$$-$(date +%s)" - 解锁必须用 Lua 脚本原子执行,防止误删他人锁
- 超时时间要略大于脚本最大预期耗时,避免锁提前释放

















