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]
内容来源于网络如有侵权请私信删除

文章来源: 博客园

原文链接: https://www.cnblogs.com/zhanchenjin/p/17159875.html

你还没有登录,请先登录注册
  • 还没有人评论,欢迎说说您的想法!