面试问Redis锁,我脸都绿了……

本人花费半年的时间总结的《Java面试指南》已拿腾讯等大厂offer,已开源在github ,欢迎star!

本文GitHub https://github.com/OUYANGSIHAI/JavaInterview 已收录,这是我花了6个月总结的一线大厂Java面试总结,本人已拿大厂offer,欢迎star

原文链接:blog.ouyangsihai.cn >> 面试问Redis锁,我脸都绿了……

笔者今天带来一篇关于 Redis 锁的文章,连敲带画码出此文,有一些细节,对 Redis 锁不清晰的盆友不妨瞧一瞧。

如果是有经验的盆友,挑挑毛病,那笔者是更感谢了!闲话不多,马上发车。

谈起 Redis 锁,下面三个,算是出现最多的高频词汇:

  • **Setnx**
  • **RedLock**
  • **Redisson**
  • Setnx

    一般代指 Redis 中对 Set 命令加上 NX 参数进行使用,Set 这个命令,目前已经支持这么多参数可选:

    
    SET key value [EX seconds|PX milliseconds] [NX|XX] [KEEPTTL]
    

    当然了,就不在文章中默写 API 了,基础参数还有不清晰的,可以蹦到官网。

    面试问Redis锁,我脸都绿了......

    那么为什么要使用 PX 30000 去设置一个超时时间?是怕进程 A 不讲道理啊,锁没等释放呢,万一崩了,直接原地把锁带走了,导致系统中谁也拿不到锁。

    面试问Redis锁,我脸都绿了......

    就算这样,还是不能保证万无一失。如果进程 A 又不讲道理,操作锁内资源超过笔者设置的超时时间,那么就会导致其他进程拿到锁,等进程 A 回来了,回手就是把其他进程的锁删了,如图:

    面试问Redis锁,我脸都绿了......

    当进程 B 操作完成,去释放锁的时候(图中 T8 时刻):

    面试问Redis锁,我脸都绿了......

    当解锁的时候,先获取 Value 判断是否是当前进程加的锁,再去删除。伪代码:

    
    String uuid = xxxx;
    // 伪代码,具体实现看项目中用的连接工具
    // 有的提供的方法名为set 有的叫setIfAbsent
    set Test uuid NX PX 3000
    try{
    // biz handle....
    } finally {
        // unlock
        if(uuid.equals(redisTool.get('Test')){
            redisTool.del('Test');
        }
    }
    

    这回看起来是不是稳了?相反,这回的问题更明显了,在 Finally 代码块中,Get 和 Del 并非原子操作,还是有进程安全问题。

    面试问Redis锁,我脸都绿了......
  • 搞清劣势所在,才能更好的完善。
  • 上文中最后这段代码,还是有很多公司在用的。
  • 大公司实现规范,但是小司小项目虽然存在不严谨,可并发倒也不高,出问题的概率和大公司一样低。

    – 鲁迅

    面试问Redis锁,我脸都绿了......

    那么删除锁的正确姿势之一,就是可以使用 Lua 脚本,通过 Redis 的 eval/evalsha 命令来运行:

    
    -- lua删除锁:
    -- KEYS和ARGV分别是以集合方式传入的参数,对应上文的Test和uuid。
    -- 如果对应的value等于传入的uuid。
    if redis.call('get', KEYS[1]) == ARGV[1] 
        then 
        -- 执行删除操作
            return redis.call('del', KEYS[1]) 
        else 
        -- 不成功,返回0
            return 0 
    end
    
    
    1. setnx Test uuid
    2. expire Test 30
    

    如果有缘你也阅读过这篇文章,并且学到了这个套路,作为本文的笔者我要加一句提醒:请注意你的工作年限!首先回答官网表明即将废弃的命令,再引出 Set 命令七年前的“新特性”,如果是刚毕业不久的人这么说,面试官会以为自己穿越了。

    **你套路面试官,面试官也会套路你。  **

    – vt・沃兹基硕德

    Redisson

    但是 Redisson 这个客户端可有点厉害,笔者在官网截了仅仅是一部分的图:

    面试问Redis锁,我脸都绿了......

    笔者也非常严谨的思考了一下:这么厉害的东西哪能写废代码?

    面试问Redis锁,我脸都绿了......  

    其实笔者仔细看了一下,加锁解锁的 Lua 脚本考虑的非常全面,其中就包括锁的重入性,这点可以说是考虑非常周全,我也随手写了代码测试一下:

    面试问Redis锁,我脸都绿了......

    RedLock

    面试问Redis锁,我脸都绿了......

    笔者大概画了一下对红锁的理解:

    面试问Redis锁,我脸都绿了......
  • **顺序向五个节点请求加锁**
  • **根据一定的超时时间来推断是不是跳过该节点**
  • **三个节点加锁成功并且花费时间小于锁的有效期**
  • **认定加锁成功**
  • 回头看看 Redis 官网关于红锁的描述,就在这篇描述页面的最下面,你能看到著名的关于红锁的神仙打架事件。

    面试问Redis锁,我脸都绿了......
  • **Martin Kleppmann 的质疑贴**
  • **Antirez 的反击贴**
  • 总结

    作者:Vt

    编辑:陶家龙

    出处:https://juejin.im/post/5e61a454e51d4526f071e1df

    END

    Java面试题专栏

    面试问Redis锁,我脸都绿了......

    欢迎长按下图关注公众号后端技术精选

    面试问Redis锁,我脸都绿了......

    原文始发于微信公众号(后端技术精选):

    本人花费半年的时间总结的《Java面试指南》已拿腾讯等大厂offer,已开源在github ,欢迎star!

    本文GitHub https://github.com/OUYANGSIHAI/JavaInterview 已收录,这是我花了6个月总结的一线大厂Java面试总结,本人已拿大厂offer,欢迎star

    原文链接:blog.ouyangsihai.cn >> 面试问Redis锁,我脸都绿了……