Redis分布式锁的实现、优化与Redlock算法探讨

Redis分布式锁最简单的实现

要实现分布式锁,首先需要Redis具备“互斥”能力,这可以通过SETNX命令实现。SETNX表示SET if Not Exists,即如果key不存在,才会设置它的值,否则什么也不做。利用这一点,不同客户端就能实现互斥,从而实现一个分布式锁。

举例:

  • 客户端1申请加锁,加锁成功:
  • 客户端2申请加锁,由于它后到达,所以加锁失败:

加锁成功

当加锁成功的客户端操作完共享资源后,需要及时释放锁,通常通过DEL命令删除这个key即可。

释放锁

避免死锁

如果加锁的客户端出现异常或挂掉,那么可能会造成死锁现象,为避免这种情况,可以给锁设置一个过期时间:

SETNX lock 1    // 加锁
EXPIRE lock 10  // 10s后自动过期

加锁及过期

但是,由于SETNX和EXPIRE是两条命令,无法保证其原子性,因此有可能只执行了SETNX,未执行EXPIRE。为了解决这个问题,可以使用Redis 2.6.12之后扩展的SET命令:

SET lock 1 EX 10 NX

SET EX NX

防止锁被其他客户端释放

为防止锁被其他客户端释放,可以在加锁时设置一个只有自己知道的“唯一标识”:

SET lock $uuid EX 20 NX

释放锁时,先检查锁是否归自己持有:

if redis.get("lock") == $uuid:
    redis.del("lock")

由于GET和DEL不是原子操作,可以使用Lua脚本来保证原子性:

if redis.call("GET",KEYS[1]) == ARGV[1]
then
    return redis.call("DEL",KEYS[1])
else
    return 0
end

Java代码实现分布式锁

package com.msb.redis.lock;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.params.SetParams;

import java.util.Arrays;
import java.util.UUID;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;

@Component
public class RedisDistLock implements Lock {
   

    private final static int LOCK_TIME = 5*1000;
    private final static String RS_DISTLOCK_NS = "tdln:";
    private final static String RELEASE_LOCK_LUA =
            "if redis.call('get',KEYS[1])==ARGV[1] then\n" +
                    "        return redis.call('del', KEYS[1])\n" +
                    "    else return 0 end";
    private ThreadLocal<String> lockerId = new ThreadLocal<>();
    private Thread ownerThread;
    private String lockName = "lock";

    @Autowired
    private JedisPool jedisPool;

    public String getLockName() {
   
        return lockName;
    }

    public void setLockName(String l

相关推荐

  1. redis分布式-----基于RedLock算法实现分布式

    2024-06-17 00:32:03       44 阅读
  2. Redlock分布式

    2024-06-17 00:32:03       40 阅读
  3. Redis实现分布式

    2024-06-17 00:32:03       46 阅读
  4. Redis分布式实现

    2024-06-17 00:32:03       49 阅读

最近更新

  1. docker php8.1+nginx base 镜像 dockerfile 配置

    2024-06-17 00:32:03       98 阅读
  2. Could not load dynamic library ‘cudart64_100.dll‘

    2024-06-17 00:32:03       106 阅读
  3. 在Django里面运行非项目文件

    2024-06-17 00:32:03       87 阅读
  4. Python语言-面向对象

    2024-06-17 00:32:03       96 阅读

热门阅读

  1. 力扣2594.修车的最少时间

    2024-06-17 00:32:03       30 阅读
  2. wifiphisher详细安装教程

    2024-06-17 00:32:03       27 阅读
  3. linux安装Vsftpd

    2024-06-17 00:32:03       32 阅读
  4. 力扣爆刷第149天之TOP100五连刷(LRU、K个一组)

    2024-06-17 00:32:03       30 阅读
  5. python嵌套指南

    2024-06-17 00:32:03       28 阅读
  6. CAPL如何在底层模拟TCP Client端断开TCP连接

    2024-06-17 00:32:03       24 阅读