可靠性
为了确保分布式锁可用,至少需要确保锁的实现同时满足以下四个条件:
1.互斥性。在任意时刻,只有一个线程能拿到锁。
2.不会发生死锁。当一个线程持有锁的期间崩溃而没有主动解锁,要保证其他线程能加锁。
3.具有容错性。只要大部分的redis结点正常运行,线程就可以加锁和解锁。
4.解铃还须系铃人。加锁和解锁必须是同一个线程,当前线程不能解其他线程的锁。
代码实现
加锁代码
可以看到,我们加锁就一行代码:
redis_cluster.set(key, value, ex=LOCK_EXPIRE, nx=True),这个set()方法共有四个参数:
第一个为key,我们使用key来当锁,因为key是唯一的。
第二个为value,传入value的原因就是上面所说的可靠性第四个条件解铃还须系铃人,通过传入value,我们就知道这把锁是哪个请求加的了,value可以通过uuid.uuid1().hex方法生成,uuid表示全局唯一标识符,不知道的同学自行百度。
第三个为ex,意思是我们要给这个key设置一个过期时间。
第四个为默认参数nx=True,意思SET IF NOT EXIST,就是当key不存在时才进行set操作,若key已经存在,则不做任何操作。
总的来说,执行上面的set()方法会有两种结果:
1.当前没有锁(key不存在),则进行加锁操作,并对锁设置过期时间,value表示拿到锁的线程。
2.当前已经有锁(key已经存在),不做任何操作。
我们的加锁代码满足前面说的可靠性里描述的三个条件。
首先,set()加入了nx=True参数,,可以保证如果key已经存在,则函数不会调用成功,也就是只有一个线程能拿到锁,满足互斥性。
其次,由于我们对锁设置了过期时间,即使锁的持有者后续发生崩溃而没有解锁,锁也会因为到了过期时间而自动解锁(即删除key),不会发生死锁。
最后,因为我们传入value,并且uuid.uuid1()方法生成的value是唯一的,代表当前前加锁的线程,那么在解锁的时候就可以判断出是否为同一线程。
网友评论