Redis分布式锁面试笔记
为什么需要分布式锁?
在微服务集群环境下,传统的单体架构本地锁(如synchronized、ReentrantLock)无法跨进程生效,容易导致数据不一致问题。分布式锁通过外部存储(如Redis)来协调多个服务实例对共享资源的访问。
Redis实现分布式锁的基本原理
核心命令:SETNX
Redis分布式锁主要利用SETNX
命令(SET if Not eXists),通过原子性操作确保同一时间只有一个客户端能获取锁。
# 获取锁(带超时时间)
SET lock_key unique_value NX EX 10# 释放锁
DEL lock_key
关键要素
- 互斥性:使用NX参数保证只有一个客户端能设置成功
- 超时机制:使用EX参数设置过期时间,防止死锁
- 唯一标识:value使用唯一值(如UUID),确保只有持锁者才能释放
锁超时时间控制策略
1. 业务时间预估
根据业务逻辑执行时间合理设置锁的过期时间,既要避免业务未完成锁就过期,又要防止死锁。
2. 锁续期机制
当业务执行时间可能超过预设时间时,通过定时任务自动延长锁的有效期。Redisson框架提供了看门狗(WatchDog)机制自动续期。
Redisson分布式锁优势
Redisson是Redis官方推荐的Java客户端,提供了完整的分布式锁解决方案:
- 自动续期机制
- 支持可重入锁
- 提供公平锁、读写锁等多种锁类型
- 解决了手动实现分布式锁的各种边界问题
可重入锁实现
通过Redis的Hash结构记录线程ID和重入次数:
key: lock_name
field: thread_id
value: reentrant_count
相同线程再次获取锁时,重入次数+1;释放锁时,重入次数-1,当计数为0时彻底释放锁。
高可用性:RedLock算法
主从复制的问题
单Redis实例存在单点故障风险,主从复制存在异步复制导致的锁丢失问题。
RedLock解决方案
在多个独立的Redis实例上创建锁(通常是奇数个,如5个),只有在超过一半的实例上成功获取锁(n/2+1)才认为获取锁成功。这样即使部分Redis实例故障,锁机制仍然有效。
面试常见问题
Q: 如何防止锁被误删?
A: 使用唯一标识符作为锁的value,释放锁时先检查标识符是否匹配。
Q: 如何处理锁的原子性释放?
A: 使用Lua脚本保证检查标识符和删除操作的原子性。
Q: 分布式锁的性能如何优化?
A: 使用Redisson的看门狗机制避免频繁续期,合理设置锁粒度,考虑使用读写锁减少竞争。
总结
Redis分布式锁是解决分布式环境下资源竞争的重要手段,从简单的SETNX到完整的Redisson解决方案,需要考虑互斥性、超时处理、可重入性和高可用性等多个维度。在实际应用中,建议直接使用Redisson等成熟框架,避免重复造轮子。