Redis分布式锁的实现

在对多进程互斥访问或者修改共享资源的时候,在多节点可能会做相同重复工作的时候,为了正确性,效率性,分布式锁就可以应用到这些场景了。

分布式锁有三大基础特性

        1.互斥性:和数据库等行锁一样互斥性是最基本的。

        2.高效高可用:获取锁要效率高,高可用,大多数锁节点正常情况下,锁管理器可以正常工作。

在单实例中实现锁,一般运用命令set key rand_value PX 2000 NX,这个命令,就是在Key不存在的时候设置key-value,过期时间为2000毫秒。这个里面的rang_value必须保证所有客户端请求的唯一性,我们要用这个值来安全释放锁。我们可以用lua脚本来安全执行锁的释放

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

redis的分布式锁做牛逼的实现方式莫非就是redis作者Antirez提出的Redlock.下面我们就来讨论学习一下这个算法。

        假设我们有5个redis Master节点,这些节点是项目独立的,部署在不同的机器上面。我们在获取锁的时候,和单例获取一样,轮流从这个5个节点上面获取锁,具体的操作流程如下:
       1.获取当前的毫秒时间戳

       2.轮流用相同的key和唯一性value在这5个节点上面去获取锁。在这里面我们要设立一个redis的请求的超时时间(相比锁的释放时间要小很多,这样才能保证最终的业务处理时间,比如锁的释放时间为2秒,这个请求超时时间为10毫秒),避免一个在一个redis节点上面阻塞过长时间。

      3.成功获取锁的节点超过一半(这里为3),获取锁的总时间为T_all小于锁的释放时间T_out。这两个条件同时成立则认为这个锁是获取成功的

     4.锁获取成功,那剩下的锁释放时间就是T_out_now = T_out-T_all.

     5.如果锁获取失败了,则客户端到每个节点上面去释放锁(包括客户端认为没有获取成功的锁)

现在我们知道了这个redlock算法的整个流程,那么这个算法的可行性和安全性有保证么?

     看官方的解释,他们认为是安全的,具体的解释为:

    大多数获取到锁的的节点,他么都有一个共同的存在时间,在这个时间内,其他的客户端是无法获取得到锁的。
 

 

但是我有一个疑问:

假设5个master节点,A线程在其中4个节点中获取到了锁,最先获取到的时间为t1,最后获取到的为t2,锁的过期时间为T,那么存在一个共同的存在时间为T-t1-t2=Tc。这4个set成功的节点肯定有陆续过期的存在,哪怕时间粒度再小。假设过期过程为,node1,node2,node3,node4(node5没有获取成功),在A线程处理的过程中,假设处理的时间大于锁的释放时间,这个时候,在这个4个节点设置的锁过期了2个,加上没有设置成功的节点5,就是有3个节点可供其他线程去获取锁,这时候其他线程获取成功了,岂不是有2个线程在同时处理一个任务了,以此类推岂不是会有多个线程同时处理一个任务的可能性呢?

 

非常欢迎有兴趣的人来探讨我这个疑问

 

 

 

 

 

 

 

 

 

 

      

 

 

你可能感兴趣的:(后端,算法,php)