必须用lua脚本续期,因其能原子校验锁的key存在且value匹配,避免网络抖动等导致误续他人锁;续期goroutine需绑定context并显式cancel,间隔设为ttl/3,ttl取业务p99耗时×2。

自动续期不是“锦上添花”,而是分布式锁在真实业务中不崩掉的底线——只要任务执行时间不可控(比如调第三方 API、批量写库、文件上传),就必须配看门狗。
为什么必须用 Lua 脚本做续期校验
直接调 client.Expire 或 client.PExpire 是危险操作:它不检查当前锁是否还属于你。网络抖动、GC 暂停、goroutine 调度延迟都可能导致你的业务还没结束,锁却已被别人抢走;此时你一续期,等于帮别人把锁“续活”了。
续期必须满足两个条件:① 锁 key 存在;② 当前 value 和你加锁时传入的 token 完全一致。只有 Lua 脚本能原子完成这个判断+操作。
推荐脚本(Go 中可直接用 redis.NewScript 封装):
if redis.call("get", KEYS[1]) == ARGV[1] then
return redis.call("pexpire", KEYS[1], ARGV[2])
else
return 0
end
- 传参顺序固定:
[]string{lockKey}+[]interface{}{lockValue, newTTLInMilli} - 返回
1表示续期成功,0表示锁已丢失或不属于你,此时应立即中止业务逻辑 - 别用
EXPIRE(秒级)而用PEXPIRE(毫秒级),避免因整数截断导致 TTL 归零
续期 goroutine 的生命周期怎么管
续期 goroutine 必须和业务上下文强绑定,不能靠“全局变量+手动 stop”这种脆弱方式。常见错误是业务函数 return 了,但续期还在跑,最后把别人的锁续到超时。
正确做法是用 context.WithCancel 派生子 ctx,并在业务结束时显式 cancel:
初始化并管理阿里云SDK Go 客户端,涵盖 sync.Once 单例、goroutine 安全、endpoint 与 region 配置、VPC 端点及调试。
- 加锁成功后,调
ctx, cancel := context.WithCancel(parentCtx) - 启动续期 goroutine 时传入该
ctx,并在循环里监听ctx.Done() - 业务函数末尾必须调
cancel(),哪怕 panic 也要 defer 执行 - 续期失败(Lua 返回 0)时,也应立刻调
cancel()并记录 warn 日志
漏掉 cancel() 是生产环境最常被忽略的泄漏点——它不会 crash,但会悄悄拖慢 Redis、干扰监控指标。
续期间隔和 TTL 怎么设才不翻车
续期间隔不是越密越好。太密(比如每 100ms 一次)会显著增加 Redis QPS;太疏(比如 > TTL/2)则大概率掉锁。
- TTL 建议设为「业务 P99 耗时 × 2」,例如导出接口 P99 是 1.3s,TTL 至少设
2 * time.Second - 续期间隔推荐
TTL / 3,比如 TTL=2s,就每 ~660ms 续一次;这个值兼顾安全性和压力 - 避免硬编码数字,建议从配置读取:
renewInterval = ttl / 3,并做下限保护(如不低于 200ms) - Redis Cluster 下注意 key 必须落在同一 slot,用 hash tag 包裹,如
{lock:order}:123
特别提醒:别把 time.Second 直接当毫秒用——Go 的 time.Duration 默认单位是纳秒,传给 Redis PX 参数时若没转成毫秒,锁可能“活”10亿秒。
etcd 方案里续租和释放的差异点
etcd 的续期逻辑和 Redis 有本质不同:它不靠 value 校验,而是靠 lease ID 绑定。只要 lease 还活着,key 就有效;lease 一撤销,key 自动消失。
- 续租用
client.KeepAliveOnce(ctx, leaseID),失败要重试或主动释放(client.Revoke) - 别依赖
KeepAlive的流式长连接——它可能静默断开,得配合心跳检测 - 释放锁只需
client.Revoke(ctx, leaseID),无需 Lua 脚本,也不用传 value - 但要注意:etcd 客户端默认不自动重连,
Revoke失败时需 fallback 到重试逻辑
etcd 更适合强一致性要求高、能接受稍高延迟的场景;Redis 更轻量,但对客户端实现精度要求更高——选哪个,取决于你愿不愿意为“少写几行 Lua”多扛一层运维复杂度。
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!










