对数据进行加锁时,首先需要获得锁,来得到对数据的排他性访问能力,对数据进行一系列操作后,将锁释放给其他程序。目前接触过的锁都是基于一个客户端的多个线程或进程之间的锁,但是对于多个客户端的分布式锁,如何保持锁的状态是值得考虑的事情。Redis 中的watch命令可以代替对数据进行加锁,但watch 命令只会在数据被其他客户端抢先修改的情况下通知执行这个命令的客户端,而不会阻止其他客户端对数据进行修改,所以Redis 这个锁是个乐观锁。随着负载的增加,watch命令也会展示出性能问题。
为此,考虑到redis 本身集成到分布式系统中的优点,我们基于redis 的 setnx 命令 来构建一个分布式锁。
首先我们构建一个 锁对象,为其提供对应的属性
# 锁对象 class Lock(object): def __init__(self, name, value): self.name = name self.value = value
上面的锁对象就是一个普通的对象,有name 和 value 两个属性
程序执行时需要去尝试获得锁
#获得锁 def getLock(conn, lock, lockExpireTime): if lock.name == '' or lock.value == '': return False if conn.setnx(lock.name, lock.value): conn.expire(lock.name,lockExpireTime) return True else: return False
上面代码就是尝试去根据锁的name 和值 以及过期时间去redis获得锁,如果没有这个锁就在redis 中新增一个锁,有的话就直接返回Flase
程序执行完就去释放锁:
# 释放锁 def releaseLock(conn, lock): if lock.name != '': conn.delete(lock.name)
释放锁就是将这个锁对象从redis 中移除即可。
实现的完整代码如下:
#!/usr/bin/env python3 # -*-coding : utf-8 -*- import redis LOCK_EXPIRE = 100 # 锁对象 class Lock(object): def __init__(self, name, value): self.name = name self.value = value #获得锁 def getLock(conn, lock, lockExpireTime): if lock.name == '' or lock.value == '': return False if conn.setnx(lock.name, lock.value): conn.expire(lock.name,lockExpireTime) return True else: return False # 尝试获得锁 def tryLock(conn, lock): return getLock(conn,lock,LOCK_EXPIRE) # 释放锁 def releaseLock(conn, lock): if lock.name != '': conn.delete(lock.name)