您好,欢迎来到12图资源库!分享精神,快乐你我!我们只是素材的搬运工!!
  • 首 页
  • 当前位置:首页 > 开发 > WEB开发 >
    Redis散布式锁踩坑不慌,这里有超全的处置方案
    时间:2020-04-28 12:03 来源:网络整理 作者:网络 浏览:收藏 挑错 推荐 打印

    行将开播:4月29日,民生银行郭庆谈商业银行金融科技赋能的探求与实际

    扫尾

    基于Redis的散布式锁对大家来说并不生疏,可是你的散布式锁有失败的时分吗?在失败的时分可曾疑心过你在用的散布式锁真的靠谱吗?以下是结合本人的踩坑阅历总结的一些阅历之谈。

    你真的需求散布式锁吗?

    用到散布式锁阐明遇到了多个进程共同拜访同一个资源的成绩,

    普通是在两个场景下会避免对同一个资源的重复拜访:

    提高效率。比如多个节点计算同一批义务,假设某个义务曾经有节点在计算了,那其他节点就不用重复计算了,以免糜费计算资源。不过重复计算也没事,不会形成其他更大的损失。也就是允许偶然的失败。

    保证正确性。这种状况对锁的要求就很高了,假设重复计算,会对正确性形成影响。这种不允许失败。

    引入散布式锁势必要引入一个第三方的基础设备,比如MySQL,Redis,Zookeeper等,这些完成散布式锁的基础设备出成绩了,也会影响业务,所以在运用散布式锁前可以思索下能否可以不用加锁的方式完成?

    不过这个不在本文的讨论范围内,本文假定加锁的需求是合理的,并且倾向于下面的第二种状况,为什么是倾向?由于不存在100%靠谱的散布式锁,看完下面的内容就明白了。

    从一个复杂的散布式锁完成说起

    散布式锁的Redis完成很常见,本人完成和运用第三方库都很复杂,至少看上去是这样的,这里就引见一个最复杂靠谱的Redis完成。

    最复杂的完成

    完成很经典了,这里只提两个要点?

    加锁和解锁的锁必须是同一个,常见的处置方案是给每个锁一个钥匙(独一ID),加锁时生成,解锁时判别。

    不能让一个资源永世加锁。常见的处置方案是给一个锁的过时时间。当然了还有其他方案,前面再说。

    一个可复制粘贴的完成方式如下:

    加锁

    public static boolean tryLock(String key, String uniqueId, int seconds) { 

        return "OK".equals(jedis.set(key, uniqueId, "NX""EX", seconds)); 

    这里其实是调用了 SET key value PX milli搜索引擎优化ncds NX。

    不明白这个命令的参考下SET key value [EX seconds|PX milliseconds] [NX|XX] [KEEPTTL]:https://redis.io/commands/set

    解锁

    public static boolean releaseLock(String key, String uniqueId) { 

        String luaScript = "if redis.call('get', KEYS[1]) == ARGV[1] then " + 

                "return redis.call('del', KEYS[1]) else return 0 end"

        return jedis.eval( 

            luaScript,  

            Collections.singletonList(key),  

            Collections.singletonList(uniqueId) 

        ).equals(1L); 

    这段完成的精髓在那个复杂的lua脚本上,先判别独一ID能否相等再操作。

    靠谱吗?

    这样的完成有什么成绩呢?

    单点成绩。下面的完成只需一个master节点就能搞定,这里的单点指的是单master,就算是个集群,假设加锁成功后,锁从master复制到slave的时分挂了,也是会出现同一资源被多个client加锁的。

    执行时间超过了锁的过时时间。下面写到为了不出现不断上锁的状况,加了一个兜底的过时时间,时间到了锁自动释放,但是,假设在这时期义务并没有做完怎样办?由于GC或许网络延迟招致的义务时间变长,很难保证义务一定能在锁的过时时间内完成。

    如何处置这两个成绩呢?试试看更复杂的完成吧。

    Redlock算法

    关于第一个单点成绩,顺着redis的思绪,接上去想到的一定是Redlock了。Redlock为了处置单机的成绩,需求多个(大于2)redis的master节点,多个master节点相互独立,没有数据同步。

    Redlock的完成如下:

    1)获取以后时间。

    2)依次获取N个节点的锁。每个节点加锁的完成方式同上。这里有个细节,就是每次获取锁的时分的过时时间都不同,需求减去之前获取锁的操作的耗时:

    比如传入的锁的过时时间为500ms;

    获取第一个节点的锁花了1ms,那么第一个节点的锁的过时时间就是499ms;

    获取第二个节点的锁花了2ms,那么第二个节点的锁的过时时间就是497ms;

    假设锁的过时时间小于等于0了,阐明整个获取锁的操作超时了,整个操作失败。

    3)判别能否获取锁成功。假设client在上述步骤中获取到了(N/2 + 1)个节点锁,并且每个锁的过时时间都是大于0的,则获取锁成功,否则失败。失败时释放锁。

    4)释放锁。对一切节点发送释放锁的指令,每个节点的完成逻辑和下面的复杂完成一样。为什么要对一切节点操作?由于散布式场景下从一个节点获取锁失败不代表在那个节点上减速失败,能够实践上加锁曾经成功了,但是前往时由于网络颤动超时了。

    以上就是大家常见的redlock完成的描画了,一眼看上去就是复杂版本的多master版本,假设真是这样就太复杂了,接上去剖析下这个算法在各个场景下是怎样被玩坏的。

    散布式锁的坑

    高并发场景下的成绩

    以下成绩不是说在并发不高的场景下不容易出现,只是在高并发场景下出现的概率更高些而已。

    功用成绩。 功用成绩来自于两个方面。

    (责任编辑:admin)