核心内容摘要
一起草com
Redis分布式锁8个常见面试题
为什么需要分布式锁场景双11秒杀10000人抢100个商品单机锁不行秒杀系统有10台服务器每台都有自己的内存锁不住其他服务器需要共享的锁所有服务器都能访问的锁 → Redis分布式锁
最简单的分布式锁怎么写错误示范// ❌ 新手最容易写的错误代码publicbooleanlock(Stringkey){Stringresultjedis.setnx(key,
;// 尝试加锁returnresult1;// 1表示加锁成功}publicvoidunlock(Stringkey){jedis.del(key);// 删除锁}⚠️ 问题在哪里死锁风险如果程序崩溃锁永远不释放误删别人锁A的锁超时释放B获得锁A醒来删了B的锁
怎么设置过期时间还是不对// ❌ 这个也有问题publicbooleanlock(Stringkey,intseconds){// 两步操作
加锁
设置过期时间Longresultjedis.setnx(key,
;if(result
{jedis.expire(key,seconds);// 设置过期returntrue;}returnfalse;}⚠️ 问题两步不是原子的如果setnx成功但expire前程序崩溃 → 锁变永久的
正确写法是怎样的// ✅ 正确的加锁一步完成publicbooleanlock(Stringkey,Stringvalue,intseconds){// 一条命令完成加锁设置过期时间Stringresultjedis.set(key,value,NX,EX,seconds);returnOK.equals(result);}// ✅ 安全的解锁publicvoidunlock(Stringkey,Stringvalue){// 用Lua脚本保证原子操作检查值再删除Stringscriptif redis.call(get, KEYS[1]) ARGV[1] then return redis.call(del, KEYS[1]) else return 0 end;jedis.eval(script,1,key,value);}✅ 关键点一条命令SET key value NX EX secondsvalue用唯一标识UUID或线程ID原子删除用Lua脚本检查再删除
锁的value为什么不能用1// ❌ 错误大家value都一样jedis.set(lock,1,NX,EX,
;// ✅ 正确每人一个唯一标识StringmyIdUUID.randomUUID().toString();jedis.set(lock,myId,NX,EX,
;场景演示线程A获得锁valueA123超时10秒 线程A执行了15秒锁在第10秒已过期 线程B获得锁valueB456 线程A终于执行完要删除锁 → 删了线程B的锁❌
业务没执行完锁过期了怎么办方案1设置合理的过期时间// 评估业务时间设置更长过期jedis.set(lock,uuid,NX,EX,
;// 设置30秒方案2自动续期看门狗// 启动一个线程定期续期newThread(()-{while(业务没执行完){Thread.sleep(
;// 8秒续一次// 如果是自己的锁就延长过期时间jedis.expire(lock,
;}}).start();
Redis主从切换会丢锁吗会这是Redis分布式锁的最大问题场景
线程A在主节点获得锁
主节点宕机锁数据还没同步到从节点
从节点变成新主节点
线程B在新主节点获得相同的锁 结果A和B同时持有了锁解决方案用RedLock算法在多个Redis实例上加锁用ZooKeeper更适合分布式锁接受风险业务上做幂等处理
实际开发用什么不要造轮子// 使用Redisson框架最省心RedissonClientredissonRedisson.create();RLocklockredisson.getLock(myLock);try{lock.lock();// 加锁自动续期// 执行业务...}finally{lock.unlock();// 解锁} 面试对比表方案优点缺点适用场景Redis单节点简单、快主从切换丢锁测试环境、不重要的锁RedLock相对可靠实现复杂、性能差重要的业务锁Redisson功能全、自动续期依赖框架推荐的生产方案ZooKeeper最可靠性能较差强一致性的场景❓ 面试
常见问题Q1: “说一下Redis分布式锁的
实现原理”答“用SET命令的NX和EX参数NX保证只有一个能设置成功EX设置过期时间防止死锁。
删除时用Lua脚本原子操作避免删别人锁。
”Q2: “Redis锁和ZooKeeper锁的区别”答RedisAP系统性能好但可能丢锁ZooKeeperCP系统可靠但性能差选择要高性能用Redis要可靠性用ZooKeeperQ3: “怎么实现可重入锁”答“在value里记录线程ID和重入次数。
加锁时如果是同一线程计数1解锁时计数-1计数为0才真正删除锁。
” 记住三句话加锁要原子SET key uuid NX EX seconds解锁要安全用Lua脚本先检查再删除生产别造轮子直接用Redisson 快速检查清单你的分布式锁设置过期时间了吗value是唯一的吗删除前检查value了吗考虑锁续期了吗知道主从切换会丢锁吗满足这5条面试官就难不倒你了