redsync.NewMutex的key命名必须带业务上下文,如"order:12345"而非硬编码"my-global-mutex",否则会导致无关请求串行化;锁粒度需最小化,混入ID、操作类型及多租户tenant_id;Lock()后须检查err并配合带deadline的context;Unlock()必须校验ok和err,禁用defer;集群模式下需用goredis/v8.Pool且启用ReadReplicas。

redsync.NewMutex 的 key 命名必须带业务上下文
直接用硬编码字符串如 "my-global-mutex" 当锁名,会导致所有请求串行化——哪怕业务逻辑完全无关(比如用户A改头像和用户B下单)。真实场景中应把锁粒度控制在最小必要范围:"order:12345"、"customer:789:assign"、"stock:item_001"。key 里混入唯一标识(ID)和操作类型,才能避免锁竞争放大。如果业务涉及多租户,还要加上 tenant_id,否则不同租户的同名资源会互相阻塞。
Lock() 调用后必须检查返回 err,且不能忽略 context 超时
mutex.Lock() 不是“调了就一定拿到锁”,它可能因网络抖动、Redis 连接池耗尽、Redlock 多数节点不可达而失败。常见错误是只判断 err != nil 就 panic 或 log 后继续执行,这等于绕过锁保护。正确做法是:明确设置带 deadline 的 context.WithTimeout,并在 err 非 nil 时直接返回错误或降级(如拒绝请求、写入重试队列)。另外,Lock() 默认不重试,若需自动重试,得手动包装循环 + sleep,但要注意避免雪崩式重试。
Unlock() 必须校验返回值 ok,且不能 defer 执行
mutex.Unlock() 返回两个值:ok bool 和 err error。ok == false 表示释放失败——最常见原因是锁已过期被自动清除,或当前 client 并非加锁者(value 不匹配)。如果只检查 err 而忽略 ok,就会误以为锁已释放,导致后续逻辑在无锁状态下运行。更关键的是,defer mutex.Unlock() 是危险的:一旦 Lock() 失败,defer 仍会执行,触发对不存在锁的释放操作,浪费一次 Redis 请求,还可能掩盖真正问题。务必把 Unlock() 放在 Lock() 成功后的显式位置,并配对检查 ok。
集群模式下 redsync.New() 必须用 goredis/v8.Pool,且 client 需启用 ReadReplicas
单机模式用 goredislib.NewClient + goredis.NewPool 即可,但集群模式下,若直接传入 redis.ClusterClient,redsync 会 panic —— 它要求底层 Pool 实现 redis.Pool 接口,而 ClusterClient 不满足。正确方式是用 goredis/v8 提供的 redis.NewClusterClient 创建 client,再通过 goredis.NewPool 包装;同时,为提升读取性能(如锁状态探测),client 配置中要开启 ReadOnly: true 和 RouteByLatency: true。另外,Redlock 算法依赖多数节点响应,集群节点数必须 ≥ 3,且各节点间网络延迟需稳定,否则 Lock() 可能因超时判定失败。
立即学习“go语言免费学习笔记(深入)”;
redsync 的防误删靠 value 随机 UUID 实现,但这个值不暴露给使用者;真正容易被忽略的是:它的默认锁过期时间是 8 秒,远低于多数业务处理耗时,必须显式调用 mutex.Expiry(time.Second * 30) 设置合理 TTL,否则锁会在业务中途过期,引发并发冲突。


















