分布式锁面试题分类与详解
文章目录
一、基础
概念类
1. 什么是分布式锁?为什么需要分布式锁?
答案:
分布式锁是在分布式系统中用来协调多个节点对共享资源进行互斥访问的机制。就像单机系统中的锁一样,但作用范围扩展到多台机器。
为什么需要:
- 当多个服务实例同时操作共享资源(如数据库某条记录)时,需要保证同一时间只有一个实例能操作
- 防止重复操作(如重复支付)
- 保证数据一致性(如库存扣减)
2. 分布式锁需要满足哪些基本特性?
答案:
- 互斥性:同一时刻只有一个客户端能持有锁
- 可重入性:同一个客户端可以多次获取同一把锁
- 锁超时:防止死锁,持有锁的客户端崩溃后能自动释放
- 高可用:锁服务本身要足够可靠
- 非阻塞:获取锁失败时应该有相应处理机制
二、实现方案类
1. 基于数据库的实现方案
答案:
原理:
利用数据库的唯一约束或乐观锁实现。比如创建一张锁表,通过insert一条记录来获取锁,删除记录释放锁。
具体实现:
- 创建锁表:
lock(id, resource_name, node_info, expire_time) - 获取锁:
INSERT INTO lock VALUES(...),成功则获取锁 - 释放锁:
DELETE FROM lock WHERE resource_name=xxx AND node_info=xxx - 超时处理:定时任务清理过期锁
优缺点:
- 优点:实现简单,依赖少
- 缺点:性能差,数据库压力大,非高可用
2. 基于Redis的实现方案
答案:
原理:
利用Redis的SETNX命令(SET if Not eXists)实现原子性操作。
常见实现:
// 获取锁
SET resource_name my_random_value NX PX 30000
// 释放锁
if redis.call("get",KEYS[1]) == ARGV[1] then
return redis.call("del",KEYS[1])
else
return 0
end
关键点:
- 必须设置过期时间(PX参数)
- value要唯一(如UUID),防止误删其他客户端的锁
- 释放锁时要验证value,确保只能释放自己持有的锁
RedLock算法:
Redis官方推荐的分布式锁算法,在多个独立的Redis节点上获取锁,当大多数节点获取成功才算真正获取锁。
3. 基于Zookeeper的实现方案
答案:
原理:
利用Zookeeper的临时顺序节点和Watcher机制实现。
实现步骤:
- 在指定路径下创建临时顺序节点
- 检查自己是否是最小序号节点,是则获取锁
- 不是则监听前一个节点的删除事件
- 前一个节点释放锁(节点被删除)后,重新检查
- 完成业务后删除自己的节点释放锁
优势:
- 天然解决锁释放问题(临时节点在会话结束自动删除)
- 通过Watcher机制避免轮询,性能较好
- 可靠性高
三、问题与解决方案类
1. 分布式锁的死锁问题如何解决?
答案:
死锁场景:
客户端获取锁后崩溃,没有释放锁,其他客户端永远无法获取锁。
解决方案:
- 设置锁超时时间(Redis的expire,ZK的临时节点)
- 设置合理的超时时间,防止业务未完成锁就过期
- 实现锁续约机制(看门狗机制),业务执行期间定期延长锁时间
2. 如何处理锁被其他客户端误删?
答案:
场景:
客户端A获取锁,执行时间过长导致锁过期自动释放,客户端B获取锁,此时A执行完释放锁,误删了B的锁。
解决方案:
- 锁value设置为唯一标识(如UUID)
- 释放锁时先检查value是否匹配
- Redis中使用Lua脚本保证检查+删除的原子性
3. 如何实现可重入分布式锁?
答案:
原理:
同一个线程可以多次获取同一把锁,需要记录持有锁的线程和重入次数。
实现方式:
- Redis实现:使用Hash结构,field为线程标识,value为重入次数
- ZK实现:在节点数据中记录线程信息和重入次数
- 每次重入时增加计数,释放时减少计数,计数为0时真正释放
四、高级话题类
1. 分布式锁在CAP理论中的取舍
答案:
- CP系统(如Zookeeper):优先保证一致性和分区容错性,牺牲部分可用性
- AP系统(如Redis):优先保证可用性和分区容错性,牺牲强一致性
选择依据:
- 强一致性需求高选ZK
- 高可用需求高选Redis
- 极端场景可用RedLock折中
2. 如何设计一个高可用的分布式锁服务?
答案:
设计要点:
- 多实例部署:避免单点故障
- 故障自动转移:主从切换
- 监控告警:锁等待时间、获取失败率等
- 降级方案:锁服务不可用时本地锁或排队机制
- 性能优化:避免锁成为系统瓶颈
3. 分布式锁与分布式事务的关系
答案:
区别:
- 分布式锁:解决资源互斥访问问题
- 分布式事务:保证跨服务的数据一致性
联系:
- 分布式事务中可能会用到分布式锁来保证资源隔离性
- 但分布式锁不能替代分布式事务,它只是其中一个工具
五、实战场景类
1. 秒杀系统中如何使用分布式锁?
答案:
典型场景:
防止超卖,保证库存扣减的原子性。
实现方案:
- 用户下单时先获取商品ID对应的分布式锁
- 查询并校验库存
- 扣减库存
- 释放锁
优化点:
- 锁粒度要细(按商品ID加锁)
- 锁等待时间设置合理(避免长时间阻塞)
- 可采用分段锁提升并发性能
2. 分布式锁在缓存更新中的应用
答案:
缓存击穿场景:
热点key过期,大量请求同时访问数据库。
解决方案:
// 伪代码
value = cache.get(key);
if (value == null) {
if (lock.tryLock()) {
try {
// 再次检查,防止其他线程已经更新
value = cache.get(key);
if (value == null) {
value = db.get(key);
cache.set(key, value);
}
} finally {
lock.unlock();
}
} else {
// 获取锁失败,短暂等待后重试或返回旧值
}
}
3. 如何选择合适的分布式锁实现?
答案:
选择依据:
- Redis:
- 适合性能要求高、允许偶尔锁失效的场景
- 需要自己处理锁超时、续约等问题
- 集群环境下可用RedLock算法
- Zookeeper:
- 适合强一致性要求的场景
- 可靠性高,但性能相对较低
- 适合锁竞争不激烈的场景
- 数据库:
- 适合简单场景,系统规模不大
- 不需要引入额外中间件
- 性能最差,不推荐高并发场景
9550

被折叠的 条评论
为什么被折叠?



