如何基于 Redis 实现一个最简易的分布式锁

有的时候博客内容会有变动,首发博客是最新的,其他博客地址可能会未同步,认准https://blog.zysicyj.top

全网最细面试题手册,支持艾宾浩斯记忆法。这是一份最全面、最详细、最高质量的 java面试题,不建议你死记硬背,只要每天复习一遍,有个大概印象就行了。 https://store.amazingmemo.com/chapterDetail/1685324709017001`

基于 Redis 实现一个最简易的分布式锁

分布式锁是一种在不同机器上的不同进程之间同步操作的工具。在分布式系统中,因为资源不再受单一实例控制,传统的加锁方法(如 synchronized 或者 Lock)就不再适用。Redis 由于其天然的高性能和键过期特性,成为实现分布式锁的一个很好的选择。

以下是实现最简易的分布式锁的基本步骤:

1. 创建锁

要创建一个分布式锁,你需要确保锁在 Redis 中是唯一的。这通常通过使用 SETNX 命令来实现,SETNX 是“SET if Not eXists”的缩写。

public boolean lock(String lockKey, String uniqueValue, int lockExpireTime) {
    Jedis jedis = new Jedis("localhost"); // Assuming Redis server is on localhost
    String result = jedis.set(lockKey, uniqueValue, "NX", "EX", lockExpireTime);
    
    // 判断是否成功获取到了锁
    if ("OK".equals(result)) {
        return true;
    }
    return false;
}

这段代码尝试在 Redis 中设置一个锁,key 是 lockKey,value 是 uniqueValue,而且只有在 lockKey 不存在时才会成功设置(NX 选项)。EX 表示我们设置了这个锁的过期时间(lockExpireTime),避免死锁的情况。

uniqueValue 通常是一个随机生成的 UUID,这样只有锁的持有者才能释放它。

2. 释放锁

当操作完成时,我们需要释放锁,以允许其他系统的进程获取它。

public boolean unlock(String lockKey, String uniqueValue) {
    Jedis jedis = new Jedis("localhost"); // Assuming Redis server is on localhost
    
    // 使用 Lua 脚本来保证原子性
    String script = 
            "if redis.call('get', KEYS[1]) == ARGV[1] then" +
            "   return redis.call('del', KEYS[1])" +
            "else" +
            "   return 0" +
            "end";
            
    Object result = jedis.eval(script, Collections.singletonList(lockKey), Collections.singletonList(uniqueValue));
    
    // 判断是否成功释放了锁
    return "1".equals(result.toString());
}

这段代码首先检查锁是否是由当前进程持有(即检查 lockKey 对应的 value 是否等于 uniqueValue),如果是,则删除这个 key 释放锁。

使用 Lua 脚本可以保证检查和删除操作的原子性。

注意事项

  • 确保锁的安全性:使用唯一值配合 Lua 脚本确保安全地设置和释放锁。

  • 避免死锁:通过为锁设定一个过期时间来预防死锁的发生。

  • 锁的续期:在某些情况下,我们可能需要续期锁以避免在操作未完成情况下锁自动释放。

以上就是如何使用 Redis 实现一个最基本的分布式锁的步骤。

最后更新于