python使用redis分布式锁
1.使用分布式锁需要注意的细节:
(1)互斥性。任何时刻只有一个客户端能持有锁
(2)避免死锁。即使一个客户端持有锁的期间崩溃而没有主动释放锁,也需要保证后续其他客户端能够加锁成功
(3)加锁和解锁必须是同一个客户端,客户端自己不能把其他客户端加的锁给释放了。
2.使用redis实现分布式锁,主要是使用了3个命令 setnx + expire + del, 但是注意这些命令不具备原子性,
比如一个线程在setnx后抛出异常导致没有执行expire,此时会导致锁不释放并一直阻塞,所以一定要保证这
些命令搭配使用的原子性
3.了解redis的setnx命令,setnx是SET if Not eXists的简称。
setnx命令的返回特性:命令在设置成功时返回 1 , 设置失败时返回 0
中文文档地址:http://redisdoc.com/string/setnx.html
英文文档地址:https://redis.io/commands/setnx
了解redis的expire命令,设置锁过期时间
中文文档地址:http://redisdoc.com/expire/expire.html
英文文档地址:https://redis.io/commands/expire
了解redis的del命令,删除并释放锁
中文文档地址:http://redisdoc.com/database/del.html
英文文档地址:https://redis.io/commands/del
4.代码
def acquire_lock(conn, lock_name, acquire_time=125, time_out=120):
"""
Acquire a distribute lock according to redis
:param conn: type redis.client.Redis, redis connection
:param lock_name: type str, lock name
:param acquire_time: type int, The time the client waits to acquire the lock
:param time_out: type int, lock timeout time
:return: return identifier if get lock, else return false
"""
identifier = str(uuid.uuid4())
end = time.time() + acquire_time
lock = "string:lock:" + lock_name
while time.time() < end:
if conn.set(lock, identifier, ex=time_out, nx=True):
return identifier
time.sleep(1)
return False
def release_lock(conn, lock_name, identifier):
"""
Release a redis distributed lock to allow other thread acquire the lock
:param conn: type redis.client.Redis, redis connection
:param lock_name: type str, lock name
:param identifier: type str, lock value - identifier(uuid)
:return: return True if lock release success, else False
"""
unlock_script = """
if redis.call("get",KEYS[1]) == ARGV[1] then
return redis.call("del",KEYS[1])
else
return 0
end
"""
lock = "string:lock:" + lock_name
unlock = conn.register_script(unlock_script)
return unlock(keys=[lock], args=[identifier])
5.建议参考官网(https://redis.io/topics/distlock)这里有一些基于不同语言(如python、java等)实现的第三方的相对稳定的redlock
参考:
https://zhuanlan.zhihu.com/p/112016634
https://www.cnblogs.com/zknublx/p/11722074.html
问题:
安全性,如果redis节点挂了或slave提升为master期间会出现问题
性能,acquire time自旋,如果持久获取不到锁会导致线程阻塞,如果只是需要乐观锁可以这样试试。
简单使用redis分布式锁
最新推荐文章于 2022-10-21 14:30:17 发布