直接用 redsync/v4,它已规避90%的坑,内置自动重试、租期管理与redlock支持,api简洁为mutex.lock()和unlock(),需配withexpiry和withtimeout,集群部署须用hash tag,避免手写setnx引发误删、死锁等风险。

直接用 redsync/v4,别自己封装 SETNX
redsync/v4 是目前 Go 生态中最成熟、生产验证过的 Redis 分布式锁库,它已帮你规避了 90% 的坑。自己手写 SetNX + Lua 释放脚本看似可控,实则极易漏掉续期逻辑、锁值校验、Redis Cluster hash tag 处理等细节。redsync 内置了自动重试、租期管理、多节点 Redlock 支持(可选),且 API 简洁:mutex.Lock() 和 mutex.Unlock() 即可完成全流程。
常见错误现象:手写锁时用 Del 直接删 key,导致误删他人锁;或用 EXPIRE 单独设过期,中间崩溃造成死锁。
- 安装:
go get github.com/go-redsync/redsync/v4 - 必须传
redsync.WithExpiry(15 * time.Second),否则默认 8 秒太短,业务未完成就自动释放 - 若部署在 Redis Cluster,key 必须带 hash tag,例如
{order}:123,否则SETNX和 Lua 脚本可能落在不同节点上执行失败 - 不要省略
redsync.WithTimeout(2 * time.Second),防止网络卡顿阻塞整个 goroutine
etcd 锁更适合强一致性场景,但别跳过 lease 续租
如果你的系统对锁的可靠性要求极高(比如金融类任务调度、配置变更原子性),etcd 是比 Redis 更稳的选择——它的 Txn + Lease 组合天然支持服务端 CAS 和自动回收,不存在主从不一致风险。但代价是性能略低,且客户端必须主动续租,否则 lease 过期后锁立即失效。
容易踩的坑:用 client.Grant(ctx, ttl) 申请 lease 后,没调 client.KeepAliveOnce(ctx, leaseID),或忽略返回的 <code>context.DeadlineExceeded 错误,导致锁悄无声息丢失。
- 加锁必须走
concurrency.NewSession+concurrency.NewMutex,不要绕过 session 自己拼 txn - 续租频率建议为 lease TTL 的 1/2(如 TTL=30s,则每 15s 续一次),太频繁增加 etcd 压力,太慢易触发过期
- 抢锁失败时,用
mutex.TryLock并检查 error 是否为concurrency.ErrLocked,而非靠 sleep 轮询
别在锁里做耗时操作,尤其别嵌套锁或跨服务调用
分布式锁的持有时间越短越好。实际项目中,80% 的锁超时问题源于业务逻辑本身耗时失控——比如在锁内调用外部 HTTP 接口、查慢 SQL、或做大量计算。这不仅拖长锁持有时间,还放大了锁争抢和雪崩风险。
典型错误场景:订单创建流程中,在锁内同步调用支付网关回调接口,结果支付方响应延迟 3s,导致后续所有请求排队等待。
- 锁只包裹「真正需要互斥的最小临界区」,例如:读取当前库存 → 判断是否充足 → 更新库存字段,三步
- 所有 IO 操作(HTTP、DB、RPC)一律放到锁外,或用异步队列解耦
- 绝对避免锁内再尝试获取另一个分布式锁,极易引发死锁,且无法被 Redis 或 etcd 检测
- 如果业务天然需要长时持有(如大文件上传校验),改用「预占 + 异步确认」模式,而非延长锁 TTL
监控和排查必须前置,不能等线上报警才看
分布式锁出问题往往不报错,而是表现为“看起来没生效”或“大量请求卡住”,等你发现时已经影响面扩大。最有效的防御方式是在模块初始化时就埋好观测点。
最容易被忽略的是锁等待时长统计和失败归因。比如 redsync 默认不暴露等待耗时,你得包装一层 mutex.LockWithCtx 并记录 time.Since(start);etcd 的 TryLock 失败时,要打印当前持有者的 value(通过 WithPrevKV 获取),否则根本不知道谁占着锁不放。
- 记录每次
Lock()的耗时分布(P99 > 500ms 就该告警) - 释放锁前打日志,包含锁 key、持有时长、goroutine ID,便于关联 trace
- 对 Redis 锁,定期扫描过期 key 数量突增(可能续期失败堆积);对 etcd,监控 lease 的
KeepAlive成功率
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!











