Redsync 默认不安全,需手动增强:设唯一client value防误删、用Redlock多节点防脑裂、加context超时与defer解锁兜底。

Redsync 能用,但不是“开箱即用就安全”的分布式锁——它默认只做单节点 SET NX PX,不自动续期、不防误删、不处理主从脑裂,直接拿去保护扣库存或幂等写入,大概率出问题。
redsync.NewMutex() 为什么不能直接用于生产关键路径
它底层调用的是 SET key value NX PX expiry,看似原子,但实际有三个致命缺口:
-
value是固定字符串(如"redsync"),不是 per-client 随机值 → 任意客户端都能调Unlock()删除别人的锁 - 没有看门狗机制 → 锁超时后业务还在跑,后续操作可能被其他实例覆盖
- 只连一个 Redis 实例 → 主从切换时,新主上无锁记录,多个客户端同时 acquire 成功
也就是说,mutex.Lock() 成功 ≠ 你真正持有了排他锁;mutex.Unlock() 执行了 ≠ 锁被正确释放。这是很多线上事故的起点。
必须重写 NewMutex 并注入 client-specific value
Redsync 允许传入自定义 value,但默认没暴露。你需要手动构造 *Mutex 并设置 value 字段:
立即学习“go语言免费学习笔记(深入)”;
mutex := rs.NewMutex("order_12345")
// 必须在 Lock 前设置唯一 value,否则 Unlock 会误删
mutex.Value = fmt.Sprintf("%s:%d", uuid.New().String(), time.Now().UnixNano())
这个 value 要满足两个条件:
使用 Python 脚本下载 Docker 镜像并打包为 tar 文件。用户说“下载镜像”“拉取镜像”“pull xxx”“帮我下载 nginx 镜像”等时触发。支持 SOCKS5 代理直连(推荐)和国内镜像站加速两种模式。
- 全局唯一(UUID + nanotime 基本够用)
- 能被
Unlock()的 Lua 脚本识别并校验 → Redsync 内部的release函数会先GET键值再比对,所以你设的value必须和加锁时一致
漏掉这一步,Unlock() 就退化成无条件 DEL,高并发下极易出现 A 删 B 锁、B 业务被中断的情况。
单节点 redsync 无法规避 Redis 主从脑裂
Redsync v4 默认走单 Redis 客户端(goredis/v8 或 redigo),它不实现 Redlock 算法。即使你配置了哨兵或集群地址,只要底层 pool 只连一个 endpoint,就仍是单点故障模型。
如果你的 Redis 是主从架构(非 Redis Cluster 模式),且对锁强一致性有要求(比如金融类扣款),必须手动启用 Redlock:
- 初始化至少 3 个独立的 Redis 客户端(不同物理节点)
- 用
redsync.New(redigo.NewPool(...), redigo.NewPool(...), ...)构造 multi-pool 实例 - 加锁时需成功写入 ≥ N/2+1 个节点才视为 lock 成功
注意:Redlock 在网络分区时仍可能违反安全性(CAP 中的 C),但它比单节点方案更能扛住常见故障。别指望它 100% 安全,而是把它当作“比单点好得多”的折中选择。
业务代码里必须带超时 + defer unlock
Redsync 的 Lock() 默认阻塞等待,没超时控制。生产环境必须显式加 ctx timeout:
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()
if err := mutex.LockContext(ctx); err != nil {
// 处理获取锁失败:重试?降级?返回错误?
return errors.New("acquire lock timeout")
}
defer func() {
if ok, err := mutex.Unlock(); !ok || err != nil {
log.Printf("unlock failed: %v", err)
// 这里不能 panic,也不能忽略 —— 要记录告警,因为锁可能滞留
}
}()
最容易被忽略的一点:即使 LockContext() 返回 error,也要确保不会执行 defer unlock(否则可能 unlock 一个根本没拿到的锁,触发 panic)。Redsync 不保证 unlock 前必须 lock 成功,所以你的 defer 逻辑得自己兜底判断。

















