题目
基于Redis实现分布式锁及其锁续期方案
信息
- 类型:问答
- 难度:⭐⭐
考点
分布式锁原理,Redis实现方案,锁续期机制,死锁预防
快速回答
实现Redis分布式锁的核心要点:
- 使用SET命令的NX和PX参数保证原子性:
SET lock_key unique_value NX PX 30000 - 通过唯一值(如UUID)验证锁持有者,避免误删
- 锁续期方案:
- 启动后台线程定期延长锁过期时间
- 使用Redisson的watchdog机制自动续期
- 释放锁时使用Lua脚本保证原子操作:
if redis.call('get', KEYS[1]) == ARGV[1] then return redis.call('del', KEYS[1]) else return 0 end
1. 分布式锁核心原理
在分布式系统中协调多节点对共享资源的访问,需满足:
- 互斥性:同一时刻只有一个客户端持有锁
- 防死锁:持有锁的客户端崩溃后锁能自动释放
- 容错性:Redis节点故障时仍能正常工作(需集群方案)
2. Redis实现方案
加锁操作(原子命令):
SET resource_name my_random_value NX PX 30000NX:仅当key不存在时设置PX 30000:设置30秒过期时间my_random_value:全局唯一ID(如UUID),用于安全释放锁
释放锁(Lua脚本保证原子性):
if redis.call("get",KEYS[1]) == ARGV[1] then
return redis.call("del",KEYS[1])
else
return 0
end3. 锁续期机制(Watchdog)
问题:业务操作超时导致锁提前释放
解决方案:
- 后台守护线程:
// 伪代码示例 void renewLock() { while (lockHeld) { if (redis.get(lockKey) == myId) { redis.expire(lockKey, 30); // 续期30秒 } sleep(10); // 每10秒检查一次 } } - Redisson框架实现:
- 客户端加锁成功后启动watchdog线程
- 默认每10秒续期一次(续期时间=锁超时时间/3)
- 客户端主动释放锁时停止续期线程
4. 最佳实践
- 锁命名规范:使用业务相关前缀(如
order_lock:{orderId}) - 超时时间设置:根据业务峰值耗时设置,建议比平均耗时长20%-50%
- 集群部署:使用RedLock算法(多主节点部署)增强可靠性
- 框架选择:优先使用Redisson等成熟框架,避免重复造轮子
5. 常见错误
- 误删其他客户端锁:未验证随机值直接删除
- 未设置超时:客户端崩溃导致死锁
- 单点故障:使用单Redis实例未考虑高可用
- 锁续期失败:未处理网络波动导致续期命令丢失
6. 扩展知识
- RedLock算法:在N个独立Redis节点上尝试获取锁(N通常为奇数)
- ZooKeeper对比:基于临时顺序节点实现,强一致性但性能低于Redis
- 锁粒度优化:细粒度锁(如订单ID级)比粗粒度锁(整个服务级)并发度高
- 锁重入问题:同一线程多次获取锁需特殊处理(Redisson支持可重入锁)