sync.mutex不能跨进程用,因其仅在单进程内存内生效,多实例间互不感知,导致并发修改共享资源;真正分布式锁需依赖redis(原子set+lua解锁)或etcd(lease续租)等外部协调服务。

为什么 sync.Mutex 不能跨进程用
分布式锁要解决的是多个独立进程(比如不同机器上的 Go 程序)对同一资源的互斥访问,而 sync.Mutex 只在单个 Go 进程内存内生效。它底层依赖 CPU 的原子指令(如 XCHG)和 goroutine 调度器协作,一旦进程重启、服务扩容或部署到多台机器,锁状态就完全丢失或失效。
常见错误现象:本地测试时一切正常,一上 Kubernetes 就出现重复扣款、任务双跑——本质是每个 Pod 都有自己的 sync.Mutex 实例,彼此毫无感知。
- 别把
sync.RWMutex或sync.Once当分布式锁用 - 哪怕用了
gorilla/sessions或 Redis session,也不等于有了分布式锁 - 语言学习阶段容易混淆「并发控制」和「分布式协调」——前者管 goroutine,后者管进程/节点
Redis + SETNX 是最简可行方案,但要注意 SET 的 EX 和 NX 必须原子执行
Go 生态里最常用的是 github.com/go-redis/redis/v9,关键不是调用 SetNX,而是确保过期时间(TTL)和获取锁同时完成,否则可能死锁。
错误写法:client.SetNX(ctx, "lock:key", "1", 0).Err() —— 没设 TTL,锁永不释放;或者先 SetNX 再 Expire,中间崩溃就漏锁。
Redis 缓存和数据结构管理技能。通过自然语言操作 Redis,支持 String、Hash、List、Set、ZSet、Stream 等数据结构操作。当用户提到 Redis、缓存、消息队列、会话存储时使用此技能。
- 正确姿势是用
client.Set(ctx, "lock:key", "token", &redis.Options{NX: true, EX: 30}).Err() - token 必须唯一(建议用
uuid.NewString()),用于解锁时校验,防止误删他人锁 - 解锁必须用 Lua 脚本:
EVAL "if redis.call('get',KEYS[1]) == ARGV[1] then return redis.call('del',KEYS[1]) else return 0 end" 1 lock:key token
etcd 的 CompareAndSwap 更适合强一致性场景,但 Go 客户端默认不带 lease 自动续期
etcd 的 lease 机制天然支持租约续期,比 Redis 手动续期更可靠,尤其适合长时间持有锁(如批量导入任务)。但官方 go.etcd.io/etcd/client/v3 的 Grant 返回 lease ID 后,续期得自己起 goroutine 调用 KeepAlive。
容易踩的坑:忘记监听 KeepAlive 的 channel,或没处理 context.Canceled 导致 goroutine 泄漏。
- 加锁用
client.Put(ctx, "lock/key", "value", clientv3.WithLease(leaseID)) - 判断是否抢锁成功,要看
resp.Header.Revision > 0且!resp.PrevKv == nil(说明是首次写入) - 不要依赖
WithFirstCreate—— 它只保证 key 不存在时创建,不保证原子性抢锁
Redlock 已被作者放弃,redis-cell 不是标准方案,生产环境优先选单 Redis 实例 + 正确的超时设计
Martin Kleppmann 早在 2016 年就指出 Redlock 在网络分区下无法保证安全性,Antirez 本人也承认其“不提供严格的正确性保证”。现在主流做法是接受「最多一次」(at-most-once)语义,靠业务层幂等+超时兜底,而不是堆复杂协议。
例如电商库存扣减:锁住商品 ID,TTL 设为 10 秒,业务逻辑执行完立刻释放;若超时未释放,由下游补偿任务(如定时扫描未完成订单)兜底,而非试图用 Redlock 强行保一致。
-
redis-cell是基于 Redis Module 的限流扩展,不是通用锁实现,Go 客户端支持弱 - Kubernetes 中用
LeaseAPI 做 leader election,比自己实现分布式锁更轻量 - 学习阶段最容易高估锁的必要性——先问:这个操作真的需要跨节点互斥吗?能不能用最终一致性+消息队列替代?
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!










