|NO.Z.00052|——————————|BigDataEnd|——|Hadoop&Redis.V05|——|Redis.v05|乐观锁|分布式锁|Redisson.v02|

一、setnx
### --- 实现原理

~~~     共享资源互斥
~~~     共享资源串行化
~~~     # 单应用中使用锁:(单进程多线程)
~~~     synchronized、ReentrantLock

~~~     # 分布式应用中使用锁:(多进程多线程)
~~~     分布式锁是控制分布式系统之间同步访问共享资源的一种方式。
~~~     利用Redis的单线程特性对共享资源进行串行化处理
二、实现方式
### --- 获取锁

~~~     # 方式1(使用set命令实现)--推荐
/**
    * 使用redis的set命令实现获取分布式锁
    * @param lockKey 可以就是锁
    * @param requestId 请求ID,保证同一性 uuid+threadID
    * @param expireTime 过期时间,避免死锁
    * @return
    */
    public boolean getLock(String lockKey,String requestId,int expireTime) {
        //NX:保证互斥性
        // hset 原子性操作 只要lockKey有效 则说明有进程在使用分布式锁
        String result = jedis.set(lockKey, requestId, "NX", "EX", expireTime);
        if("OK".equals(result)) {
            return true;
        }
        
        return false;
}
~~~     # 方式2(使用setnx命令实现) -- 并发会产生问题

    public boolean getLock(String lockKey,String requestId,int expireTime) {
        Long result = jedis.setnx(lockKey, requestId);
        if(result == 1) {
            //成功设置 进程down 永久有效 别的进程就无法获得锁
            jedis.expire(lockKey, expireTime);
            return true;
        }
        return false;
    }
### --- 释放锁

~~~     # 方式1(del命令实现) -- 并发
    /**
    * 释放分布式锁
    * @param lockKey
    * @param requestId
    */
    public static void releaseLock(String lockKey,String requestId) {
        if (requestId.equals(jedis.get(lockKey))) {
            jedis.del(lockKey);
        }
    }
~~~     # 问题在于如果调用jedis.del()方法的时候,
~~~     这把锁已经不属于当前客户端的时候会解除他人加的锁。

~~~     # 那么是否真的有这种场景?答案是肯定的,
~~~     比如客户端A加锁,一段时间之后客户端A解锁,在执行jedis.del()之前,
~~~     锁突然过期了,此时客户端B尝试加锁成功,然后客户端A再执行del()方法,
~~~     则将客户端B的锁给解除了。
~~~     # 方式2(redis+lua脚本实现)--推荐

public static boolean releaseLock(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 (result.equals(1L)) {
        return true;
    }
    return false;
}
三、存在问题
### --- 存在问题

~~~     单机:无法保证高可用
~~~     主--从:无法保证数据的强一致性,在主机宕机时会造成锁的重复获得。
四、无法续租
### --- 无法续租

~~~     超过expireTime后,不能继续使用
五、本质分析
### --- CAP模型分析
~~~     在分布式环境下不可能满足三者共存,只能满足其中的两者共存,
~~~     在分布式下P不能舍弃(舍弃P就是单机了)。
~~~     所以只能是CP(强一致性模型)和AP(高可用模型)。
~~~     分布式锁是CP模型,Redis集群是AP模型。 (base)
~~~     Redis集群不能保证数据的随时一致性,只能保证数据的最终一致性。
### --- 为什么还可以用Redis实现分布式锁?

~~~     与业务有关
~~~     当业务不需要数据强一致性时,比如:社交场景,就可以使用Redis实现分布式锁
~~~     当业务必须要数据的强一致性,即不允许重复获得锁,
~~~     比如金融场景(重复下单,重复转账)就不要使用可以使用CP模型实现,比如:zookeeper和etcd。

 
 
 
 
 
 
 
 
 

Walter Savage Landor:strove with none,for none was worth my strife.Nature I loved and, next to Nature, Art:I warm'd both hands before the fire of life.It sinks, and I am ready to depart
                                                                                                                                                   ——W.S.Landor

 

 

posted on   yanqi_vip  阅读(18)  评论(0编辑  收藏  举报

相关博文:
阅读排行:
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 记一次.NET内存居高不下排查解决与启示
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
· DeepSeek 开源周回顾「GitHub 热点速览」
< 2025年3月 >
23 24 25 26 27 28 1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28 29
30 31 1 2 3 4 5

导航

统计

点击右上角即可分享
微信分享提示