Redis分布式锁中8个常见面试题小结

 更新时间:2026年03月09日 10:03:10   作者:小坏说Java  
本文主要介绍了Redis分布式锁中8个常见面试题小结,包括使用Redis、RedLock算法和ZooKeeper等工具,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧

📌 1. 为什么需要分布式锁?

场景:双11秒杀,10000人抢100个商品

  • 单机锁不行:秒杀系统有10台服务器,每台都有自己的内存,锁不住其他服务器
  • 需要共享的锁:所有服务器都能访问的锁 → Redis分布式锁

📌 2. 最简单的分布式锁怎么写?(错误示范)

// ❌ 新手最容易写的错误代码
public boolean lock(String key) {
    String result = jedis.setnx(key, "1");  // 尝试加锁
    return result == 1;  // 1表示加锁成功
}

public void unlock(String key) {
    jedis.del(key);  // 删除锁
}

⚠️ 问题在哪里?

  1. 死锁风险:如果程序崩溃,锁永远不释放
  2. 误删别人锁:A的锁超时释放,B获得锁,A醒来删了B的锁

📌 3. 怎么设置过期时间?(还是不对)

// ❌ 这个也有问题
public boolean lock(String key, int seconds) {
    // 两步操作:1.加锁 2.设置过期时间
    Long result = jedis.setnx(key, "1");
    if (result == 1) {
        jedis.expire(key, seconds);  // 设置过期
        return true;
    }
    return false;
}

⚠️ 问题:两步不是原子的!

  • 如果setnx成功,但expire前程序崩溃 → 锁变永久的!

📌 4. 正确写法是怎样的?

// ✅ 正确的加锁(一步完成)
public boolean lock(String key, String value, int seconds) {
    // 一条命令完成:加锁+设置过期时间
    String result = jedis.set(key, value, "NX", "EX", seconds);
    return "OK".equals(result);
}

// ✅ 安全的解锁
public void unlock(String key, String value) {
    // 用Lua脚本保证原子操作:检查值再删除
    String script = 
        "if redis.call('get', KEYS[1]) == ARGV[1] then " +
        "   return redis.call('del', KEYS[1]) " +
        "else " +
        "   return 0 " +
        "end";
    
    jedis.eval(script, 1, key, value);
}

✅ 关键点:

  1. 一条命令SET key value NX EX seconds
  2. value用唯一标识:UUID或线程ID
  3. 原子删除:用Lua脚本检查再删除

📌 5. 锁的value为什么不能用"1"?

// ❌ 错误:大家value都一样
jedis.set("lock", "1", "NX", "EX", 10);

// ✅ 正确:每人一个唯一标识
String myId = UUID.randomUUID().toString();
jedis.set("lock", myId, "NX", "EX", 10);

场景演示:

线程A:获得锁,value="A123",超时10秒
线程A:执行了15秒(锁在第10秒已过期)
线程B:获得锁,value="B456"
线程A:终于执行完,要删除锁 → 删了线程B的锁!❌

📌 6. 业务没执行完,锁过期了怎么办?

方案1:设置合理的过期时间

// 评估业务时间,设置更长过期
jedis.set("lock", uuid, "NX", "EX", 30);  // 设置30秒

方案2:自动续期(看门狗)

// 启动一个线程,定期续期
new Thread(() -> {
    while (业务没执行完) {
        Thread.sleep(8000);  // 8秒续一次
        
        // 如果是自己的锁,就延长过期时间
        jedis.expire("lock", 10);
    }
}).start();

📌 7. Redis主从切换会丢锁吗?

会!这是Redis分布式锁的最大问题

场景:

1. 线程A在主节点获得锁
2. 主节点宕机(锁数据还没同步到从节点)
3. 从节点变成新主节点
4. 线程B在新主节点获得"相同"的锁
结果:A和B同时持有了锁!

解决方案:

  1. 用RedLock算法:在多个Redis实例上加锁
  2. 用ZooKeeper:更适合分布式锁
  3. 接受风险:业务上做幂等处理

📌 8. 实际开发用什么?(不要造轮子!)

// 使用Redisson框架(最省心)
RedissonClient redisson = Redisson.create();
RLock lock = redisson.getLock("myLock");

try {
    lock.lock();  // 加锁(自动续期)
    // 执行业务...
} finally {
    lock.unlock();  // 解锁
}

📊 面试对比表

方案优点缺点适用场景
Redis单节点简单、快主从切换丢锁测试环境、不重要的锁
RedLock相对可靠实现复杂、性能差重要的业务锁
Redisson功能全、自动续期依赖框架推荐的生产方案
ZooKeeper最可靠性能较差强一致性的场景

❓ 面试常见问题

Q1: "说一下Redis分布式锁的实现原理"

:"用SET命令的NX和EX参数,NX保证只有一个能设置成功,EX设置过期时间防止死锁。删除时用Lua脚本原子操作,避免删别人锁。"

Q2: "Redis锁和ZooKeeper锁的区别?"

  • Redis:AP系统,性能好,但可能丢锁
  • ZooKeeper:CP系统,可靠但性能差
  • 选择:要高性能用Redis,要可靠性用ZooKeeper

Q3: "怎么实现可重入锁?"

:"在value里记录线程ID和重入次数。加锁时如果是同一线程,计数+1;解锁时计数-1,计数为0才真正删除锁。"

📝 记住三句话

  1. 加锁要原子SET key uuid NX EX seconds
  2. 解锁要安全:用Lua脚本先检查再删除
  3. 生产别造轮子:直接用Redisson

🎯 快速检查清单

你的分布式锁:

  • 设置过期时间了吗?
  • value是唯一的吗?
  • 删除前检查value了吗?
  • 考虑锁续期了吗?
  • 知道主从切换会丢锁吗?

满足这5条,面试官就难不倒你了!

到此这篇关于Redis分布式锁中8个常见面试题小结的文章就介绍到这了,更多相关Redis分布式锁面试题内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • Redis高并发场景下秒杀超卖解决方案(秒杀场景)

    Redis高并发场景下秒杀超卖解决方案(秒杀场景)

    早起的12306购票,刚被开发出来使用的时候,12306会经常出现超卖 这种现象,也就是说车票只剩10张了,却被20个人买到了,这种现象就是超卖,今天通过本文给大家介绍Redis高并发场景下秒杀超卖解决方案,感兴趣的朋友一起看看吧
    2022-04-04
  • Redis 大key的几种删除方式

    Redis 大key的几种删除方式

    大key删除直接调用 del 命令删除key,容易造成请求被阻塞,本文主要介绍了Redis 大key的几种删除方式,具有一定的参考价值,感兴趣的可以了解一下
    2025-03-03
  • Redis解决秒杀微服务抢购代金券超卖和同一个用户多次抢购

    Redis解决秒杀微服务抢购代金券超卖和同一个用户多次抢购

    本文介绍了如何用Redis和Redisson分布式锁解决秒杀中的超卖和同一用户重复抢购问题,通过Lua脚本保证操作原子性,最终实现库存和订单的准确控制,感兴趣的可以了解一下
    2025-09-09
  • redis 主从哨兵模式实现一主二从

    redis 主从哨兵模式实现一主二从

    本文主要介绍了redis 主从哨兵模式实现一主二从,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2022-07-07
  • redis使用skiplist跳表的原因解析

    redis使用skiplist跳表的原因解析

    经常会有人问这个问题,redis中为什么要使用跳表?这个问题,redis作者已经给出过明确答案,今天通过本文再给大家讲解下这个问题,对redis skiplist跳表知识感兴趣的朋友一起看看吧
    2022-10-10
  • Redis批量删除指定前缀的Key两种方法

    Redis批量删除指定前缀的Key两种方法

    redis作为缓存服务器在项目中经常使用,使用redis存储数据时,我们经常会将key分组,这篇文章主要给大家介绍了关于Redis批量删除指定前缀的Key两种方法,需要的朋友可以参考下
    2024-01-01
  • 使用redis分布式锁解决并发线程资源共享问题

    使用redis分布式锁解决并发线程资源共享问题

    这篇文章主要介绍了使用redis分布式锁解决并发线程资源共享问题,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2019-07-07
  • 一文解决Redis后台持久化失败的问题:内存不足导致fork失败

    一文解决Redis后台持久化失败的问题:内存不足导致fork失败

    Redis作为一个内存数据库,在执行后台持久化(例如 BGSAVE 命令时)需要fork一个子进程来生成数据库快照(RDB 文件),在生产环境中,有时你可能会在Redis日志中遇到持久化失败的问题,本文将详细介绍该问题的原因以及如何通过调整内核和Redis配置来解决此问题
    2025-07-07
  • Redis和数据库的一致性(Canal+MQ) 的实现

    Redis和数据库的一致性(Canal+MQ) 的实现

    本文主要介绍了Redis和数据库的一致性(Canal+MQ),文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2025-06-06
  • Redis安装及基本数据类型

    Redis安装及基本数据类型

    这篇文章主要介绍了Redis安装及基本数据类型,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2018-05-05

最新评论