`
cnjarchen
  • 浏览: 41723 次
  • 性别: Icon_minigender_1
  • 来自: 深圳
社区版块
存档分类
最新评论

Redis分布式锁的正确实现方式

 
阅读更多

分布式锁一般有三种实现方式:

1. 数据库乐观锁;

2. 基于Redis的分布式锁;

3. 基于ZooKeeper的分布式锁。

 

 

为了确保分布式锁可用,我们至少要确保锁的实现同时满足以下四个条件:

1.互斥性。在任意时刻,只有一个客户端能持有锁。

2.不会发生死锁。即使有一个客户端在持有锁的期间崩溃而没有主动解锁,也能保证后续其他客户端能加锁。

3.具有容错性。只要大部分的Redis节点正常运行,客户端就可以加锁和解锁。

4.解铃还须系铃人。加锁和解锁必须是同一个客户端,客户端自己不能把别人加的锁给解了。

 

加锁代码

public class RedisTool {

    private static final String LOCK_SUCCESS = "OK";
    private static final String SET_IF_NOT_EXIST = "NX";
    private static final String SET_WITH_EXPIRE_TIME = "PX";

    /**
     * 尝试获取分布式锁
     * @param jedis Redis客户端
     * @param lockKey 锁
     * @param requestId 请求标识
     * @param expireTime 超期时间
     * @return 是否获取成功
     */
    public static boolean tryGetDistributedLock(Jedis jedis, String lockKey, String requestId, int expireTime) {
        String result = jedis.set(lockKey, requestId, SET_IF_NOT_EXIST, SET_WITH_EXPIRE_TIME, expireTime);

        if (LOCK_SUCCESS.equals(result)) {
            return true;
        }
        return false;
    }
}

 

可以看到,我们加锁就一行代码:

jedis.set(String key, String value, String nxxx, String expx, int time),这个set()方法一共有五个形参:

  • 第一个为key,我们使用key来当锁,因为key是唯一的。

  • 第二个为value,我们传的是requestId,很多童鞋可能不明白,有key作为锁不就够了吗,为什么还要用到value?原因就是我们在上面讲到可靠性时,分布式锁要满足第四个条件解铃还须系铃人,通过给value赋值为requestId,我们就知道这把锁是哪个请求加的了,在解锁的时候就可以有依据。requestId可以使用UUID.randomUUID().toString()方法生成。

  • 第三个为nxxx,这个参数我们填的是NX,意思是SET IF NOT EXIST,即当key不存在时,我们进行set操作;若key已经存在,则不做任何操作;

  • 第四个为expx,这个参数我们传的是PX,意思是我们要给这个key加一个过期的设置,具体时间由第五个参数决定。

  • 第五个为time,与第四个参数相呼应,代表key的过期时间。

 

解锁代码

public class RedisTool {
    private static final Long RELEASE_SUCCESS = 1L;

    /**
     * 释放分布式锁
     * @param jedis Redis客户端
     * @param lockKey 锁
     * @param requestId 请求标识
     * @return 是否释放成功
     */
    public static boolean releaseDistributedLock(Jedis jedis, String lockKey, String requestId) {
        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(requestId));

        if (RELEASE_SUCCESS.equals(result)) {
            return true;
        }
        return false;
    }
}

 

为什么要使用Lua语言来实现呢?因为要确保上述操作是原子性的。如果:

public static void wrongReleaseLock2(Jedis jedis, String lockKey, String requestId) {
    // 判断加锁与解锁是不是同一个客户端
    if (requestId.equals(jedis.get(lockKey))) {
        // 若在此时,这把锁突然不是这个客户端的,则会误解锁
        jedis.del(lockKey);
    }
}

就会有问题,比如客户端A加锁,一段时间之后客户端A解锁,在执行jedis.del()之前,锁突然过期了,此时客户端B尝试加锁成功,然后客户端A再执行del()方法,则将客户端B的锁给解除了。

 

分享到:
评论

相关推荐

    Java Redis分布式锁的正确实现方式详解

    主要介绍了Java Redis分布式锁的正确实现方式详解,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下

    Redis分布式锁存在的问题及解决方案(值得珍藏)

    Redis分布式锁在实现跨进程、跨机器的互斥访问时,虽功能强大,但也存在一些常见问题。这些问题主要源于网络延迟、系统时钟误差以及Redis自身的特性。 一个典型问题是锁的"死锁"现象,即因进程意外终止或网络故障,...

    Redis分布式锁的正确实现方法总结

    在本篇文章里小编给大家整理的是关于Redis分布式锁的正确实现方式介绍,有兴趣的朋友们可以学习下。

    浅谈Redis分布式锁的正确实现方式

    虽然网上已经有各种介绍Redis分布式锁实现的博客,然而他们的实现却有着各种各样的问题,为了避免误人子弟,本篇博客将详细介绍如何正确地实现Redis分布式锁。 可靠性 首先,为了确保分布式锁可用,我们至少要确保...

    谈谈Redis分布式锁的正确实现方法

    在昨天 review 队友代码的过程中,发现了我们组分布式锁的写法似乎有点问题,实现代码如下: 加锁部分 解锁部分 主要原理是使用了 redis 的 setnx 去插入一组 key-value,其中 key 要上锁的标识(在项目中是锁死...

    redis 分布式锁

    虽然网上已经有各种介绍Redis分布式锁实现的博客,然而他们的实现却有着各种各样的问题,将详细介绍如何正确地实现Redis分布式锁。

    Redis Template实现分布式锁的实例代码

    虽然网上已经有各种介绍Redis分布式锁实现的博客,然而他们的实现却有着各种各样的问题,为了避免误人子弟,本篇博客将详细介绍如何正确地实现Redis分布式锁。 可靠性 首先,为了确保分布式锁可用,我们至少要确保锁...

    java语言描述Redis分布式锁的正确实现方式

    主要介绍了java语言描述Redis分布式锁的正确实现方式,具有一定借鉴价值,需要的朋友可以参考下。

    基于redis分布式锁实现秒杀功能

    将业务抽象,技术角度看,秒杀就是多个线程对资源进行操作,所以实现秒杀,就必须控制线程对资源的争抢,既要保证高效并发,也要保证操作的正确。 一些可能的实现 刚才提到过,实现秒杀的关键点是控制线程对资源的...

    Redis实现分布式锁的方法示例

    锁的本质就是互斥,保证任何时候能有一个客户端持有同一个锁,如果考虑使用redis来实现一个分布式锁,最简单的方案就是在实例里面创建一个键值,释放锁的时候,将键值删除。但是一个可靠完善的分布式锁需要考虑的...

    解析分布式锁之redis实现1

    摘要:分布式架构设计如今在企业中被量的应,在不同的分布式节点进协同作的时候,节点服务的时序、结果的正确性以及执成本也成为了必须考虑的重要因素。其中竞态条件会导致

    SpringBoot整合Redis正确的实现分布式锁的示例代码

    主要介绍了SpringBoot整合Redis正确的实现分布式锁的示例代码,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧

    distched:使用 Cloud Foundry、Spring Scheduling 和 Redis 分布式锁的玩具分布式调度器

    我为的单个实例实现了页面上概述的分布式锁模式。 请参阅“使用单个实例正确实现”部分。 ##入门 git clone https://github.com/krujos/distsched cd distsched该项目使用来支持清单。 如果您想使用它,您需要...

    基于RateLimiter和Lua脚本限量控制实现分布式限流.docx

    本处涉及到分布式环境下的同步,因此将其解耦,令牌桶模型存储于Redis中,对其同步操作的控制放置在如下控制类,其中同步控制使用到了前面介绍的分布式锁(参考基于Redis分布式锁的正确打开方式)

    bigdata-practice:常用大数据工具学习实战,包含Hadoop、HBase、Kafka、ClickHouse、Hive、Redis、Zookeeper....未完待续

    Hadoop Practice ...使用redis简单正确实现分布式锁 使用Lettuce作为redis客户端实例 redis持久化详解 Zookeeper Practice 基于zookeeper的服务注册与发现 基于zookeeper实现leader选举 zookeeper的leader选举机制

Global site tag (gtag.js) - Google Analytics