加锁必须用 SET key value EX seconds NX,value 需唯一(如 uuid),解锁和续期必须用 Lua 脚本校验 value,TTL 设为业务 P99×2,长任务需看门狗续期,Redlock 多数场景不必要。加锁必须用 SET key value EX seconds NX,别信单 SetNXGo 生态里很多教程说"用 rdb.SetNX 就行",但这是错的------老版本 Redis 不支持在 SetNX 里直接设过期时间,而 Go 客户端(比如 go-redis/v9)的 SetNX(ctx, key, val, ttl) 是靠服务端 SET ... NX EX 命令实现的。如果你连的是 Redis 2.4 或没开 Lua 支持的旧实例,它会 fallback 成两步:先 SETNX,再 EXPIRE,中间一崩溃,锁就永远卡住。value 必须是每个 goroutine 独立生成的,比如 uuid.NewString();写死成 "1" 或复用字符串,解锁时根本分不清是谁的锁EX 足够,除非你要毫秒级精度(那就用 PX);但注意 Go 的 time.Second 别误转成纳秒传给 EX,否则锁 1 秒变 10 亿秒TTL 建议设为「业务 P99 耗时 × 2」,比如导出接口最长跑 1.2s,就设 2 * time.Second;太短会导致锁提前释放,太长会让故障恢复变慢解锁必须用 Lua 脚本,GET + DEL 是经典竞态很多人写完 GET 判断值相等,再调 DEL,结果 A 拿着锁还没删,B 查到过期去抢,A 一删就把 B 刚 set 的锁干掉了------这不是 bug,是必然发生的 race condition。唯一安全解法是原子脚本:EVAL "if redis.call('get', KEYS1) == ARGV1 then return redis.call('del', KEYS1) else return 0 end" 1 lock:key abc123Go 里用 redis.NewScript(unlockScript).Run(ctx, rdb, \[\]string{key}, clientID),返回 int64,非 1 就代表解锁失败,得记录日志或告警别把脚本拼在代码里,用 embed.FS 或 const 管理,方便审计和灰度上线时热替换长任务必须配看门狗续期,EXPIRE 单独调等于裸奔业务执行时间不确定,锁又不能不设 TTL(否则主从切换后锁丢失),这矛盾只能靠续期解。但乱续期更危险:A 续了 B 的锁,B 还以为自己拿着锁在改数据。续期也得用 Lua 校验:if redis.call("GET", KEYS1) == ARGV1 then return redis.call("EXPIRE", KEYS1, ARGV2) else return 0 end续期间隔建议为 TTL / 3,比如 TTL=2s,就每 600ms 续一次;太密增加 Redis 压力,太疏容易掉锁业务函数 return 前必须显式 stop 续期 goroutine,否则锁释放了,后台还在不停续------变成"幽灵续期"Redlock 不是银弹,多数场景单实例+正确实现就够用Redlock 看起来高大上,但实际落地要连 ≥3 个独立 Redis 实例、校准时钟、处理网络分区、应对幽灵锁......运维成本远超收益。除非你有金融级一致性要求,否则单实例锁只要做到 value 唯一 + Lua 解锁 + 合理 TTL + 续期,已覆盖订单幂等、库存扣减、定时任务防重跑等绝大多数场景。 幻导航网 发现优质实用网站,开启网络探索之旅!
相关推荐
Ulyanov6 分钟前
雷达导引头Python仿真框架:GPU加速、6-DOF模型与半实物仿真接口wuqingshun31415927 分钟前
MYSQL默认的事务隔离级别是什么?为什么选择这个级别?列逍37 分钟前
博客系统测试空中湖1 小时前
电池简史(五):极限之梦与终章——锂硫、锂空气、量子电池,以及你该知道的电池投资与生活指南星云开发1 小时前
拒绝无效加班!用Python打造自动化办公流,附Word/PDF互转硬核代码dream_home84072 小时前
图像算法模型NPU适配与算法服务实战指南AIGS0012 小时前
跨越语义鸿沟:企业本体语义平台的构建与落地李可以量化2 小时前
PTrade 量化策略实战:二八轮动策略深度解析(下)蓝胖子酱2 小时前
在 Electron 中用 electron-store 实现加密存储与自定义格式文件Mx_coder2 小时前
8年Java开发者AI转型第二周:RAG检索优化-从60%到90%准确率的3个关键技巧 (Day 13-14)