IT评测·应用市场-qidao123.com
标题:
redis分布式锁原子性设置超时问题
[打印本页]
作者:
水军大提督
时间:
2023-2-28 00:23
标题:
redis分布式锁原子性设置超时问题
1.问题:
最近客服有报无法上报运动记录,通过日志查看是分布式锁等待超时所致。
redis出现一个分布式锁的TTL为-1,正常情况都会设置超时时间的。
2.分析:
通过k8s发现sport服务在50几天内重启了40几次,机器上内存比较紧缺,暂时只能重启,占用内存高的问题也先不解决。
看下之前加锁的代码:
acquire_lock
def acquire_lock(redis_client, lock_key, lock_value, expire=10, timeout=5):
"""
获取锁
:param redis_client: redis;连接
:param lock_key: lock key
:param lock_value: lock value
:param expire: lock key过期时间
:param timeout: 等待超时
:return:
"""
assert isinstance(redis_client, RedisClient), [type(RedisClient), RedisClient]
wait_time = 0
sleep_time = 0.05
with redis_client.ctx_conn as conn:
while True:
stime = time.time()
if conn.execute('SETNX', lock_key, lock_value):
conn.execute('EXPIRE', lock_key, expire)
return True
elif not conn.execute('TTL', lock_key):
conn.execute('EXPIRE', lock_key, expire)
logger.info("acquire_lock :%s" % lock_key)
gevent.sleep(sleep_time)
etime = time.time()
wait_time += etime - stime
if wait_time >= timeout:
break
assert 0, [conn, lock_key, lock_value, expire, timeout]
复制代码
从现状来分析,应该是SETNX之后没有执行EXPIRE,正常执行肯定没有问题;
我估计是因为进程刚好执行到SETNX的时候被k8s杀了,导致EXPIRE没有去执行
3.解决方案:
set需要同时兼容NX EX的原子功能
研究了一下redis的set命令,果然有这个功能
SET', lock_key, lock_value, NX, EX, expire
兼容没有设置超时的时候设置一下超时
判断TTL 是-1的时候:
ttl当 key 不存在时,返回 -2 。 当 key 存在但没有设置剩余生存时间时,返回 -1 。 否则,以秒为单位,返回 key 的剩余生存时间
原子操作set
def acquire_lock(redis_client, lock_key, lock_value, expire=10, timeout=5):
"""
获取锁
:param redis_client: redis;连接
:param lock_key: lock key
:param lock_value: lock value
:param expire: lock key过期时间
:param timeout: 等待超时
:return:
"""
assert isinstance(redis_client, RedisClient), [type(RedisClient), RedisClient]
wait_time = 0
sleep_time = 0.05
logger.info("acquire_lock lock_key:%s lock_value:%s" % (lock_key, lock_value))
with redis_client.ctx_conn as conn:
while True:
stime = time.time()
if conn.execute('SET', lock_key, lock_value, "NX", "EX", expire):
return True
elif conn.execute('TTL', lock_key) == -1:
conn.execute('EXPIRE', lock_key, expire)
gevent.sleep(sleep_time)
etime = time.time()
wait_time += etime - stime
if wait_time >= timeout:
break
assert 0, [conn, lock_key, lock_value, expire, timeout]
复制代码
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!
欢迎光临 IT评测·应用市场-qidao123.com (https://dis.qidao123.com/)
Powered by Discuz! X3.4