Windows 不支持 syscall.Flock,因其是 POSIX 系统调用;分布式环境下本地文件锁(如 flock、LockFileEx)无效,因跨机器不可见、无协调机制;必须使用 Redis、etcd 等中心化服务实现真正互斥。

syscall.Flock 在 Windows 上直接 panic,flock 是 Unix/Linux 原生系统调用,Windows 根本不支持。想在分布式环境(多机器、多进程)下对同一个文件实现排他性锁定,不能靠本地文件锁,必须换思路。
为什么不能用本地文件锁做分布式互斥
本地文件锁(如 flock、fcntl、Windows 的 LockFileEx)只在单机内生效,依赖操作系统内核的文件句柄表或锁管理器。一旦跨机器,这些锁彼此不可见、无法协调——A 机器加了锁,B 机器完全感知不到,也就谈不上“排他”。
常见误操作包括:
- 在 NFS 挂载点上用
flock—— 大部分 NFS 实现不保证锁语义,flock调用可能静默成功但实际无互斥效果 - 把 Windows 的
LockFileEx当作分布式锁用 —— 它只对当前机器上的打开句柄有效,其他机器上的进程 open 同一路径后仍可任意读写 - 用 Go 的
sync.Mutex或sync.RWMutex—— 这些是进程内 goroutine 级别锁,对其他进程完全无效
真正可行的方案:基于中心化存储的分布式锁
要让多台机器达成一致,必须引入一个所有节点都信任且能原子操作的第三方服务。目前生产最常用的是 Redis 和 etcd。
Redis 方案核心是 SET key value NX EX seconds + Lua 脚本释放(防止误删),需注意:
-
NX保证只有 key 不存在时才设置成功,实现“抢占”语义 -
EX提供自动过期,避免死锁;但业务执行时间不确定时,得搭配 Watchdog 续期(如 Redisson 的机制) - value 必须是全局唯一标识(如 UUID + PID),否则解锁时可能删掉别人持有的锁
- 不要用
DEL直接删 key,必须用 Lua 脚本比对 value 再删,否则出现“锁被续期后又被误删”问题
etcd 方案则依赖 CompareAndSwap (CAS) 和租约(lease),天然支持 TTL 和自动清理,语义更严谨,适合强一致性要求场景。
文件操作流程必须配合锁生命周期
拿到分布式锁 ≠ 文件就安全了。你仍需确保:锁持有期间,所有对目标文件的读写都走同一份逻辑,并在锁释放前完成全部 I/O。
典型错误模式:
- 先获取 Redis 锁 → 打开文件 → 开始写入 → 中间某步 panic 导致没解锁 → 文件残留脏数据且锁长期占用
- 锁超时自动释放,但写操作仍在继续 → 其他节点抢到锁后也写同一文件 → 数据覆盖或错乱
正确做法是:用 defer+recover 包裹关键段,解锁逻辑必须放在 defer 中;写操作建议使用临时文件 + os.Rename 原子提交(Windows 下注意 os.Rename 对跨卷操作不保证原子性)。
没有银弹:权衡延迟、可靠性与运维成本
Redis 锁快但依赖单点或哨兵/集群稳定性;etcd 更重但一致性更强;ZooKeeper 已逐步淘汰;数据库唯一索引方案简单但性能差、扩展性弱。
最容易被忽略的一点:分布式锁从来不是“加个锁就万事大吉”,它只是同步原语的第一环。后续的文件落地方式、错误恢复策略、幂等设计、监控告警,缺一不可。
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!











