美文网首页思科DevNet
Redis 利用 incr 和 expire 来限流, 并发导致

Redis 利用 incr 和 expire 来限流, 并发导致

作者: linyk3 | 来源:发表于2018-12-19 22:09 被阅读0次

    当某一个接口需要限流时,可以采用redis的incr来递增,记录访问次数, 以及 expire 来设置失效时间.
    大概的代码如下:

        r = redis.Redis.connect()
        key = "linyk3"
        query_times = redis.Redis.get_data(r, key)
        if query_times and int(query_times) > 1000:
            print('访问次数过多,超过1000次限制!')
            return
        else:
            redis.Redis.incr(r, key)
            if redis.Redis.get_data(r, key) == 1:
                redis.Redis.expire_data(r, key, 60*60)
    

    因为redis的incr操作,当key不存在时, 会生成这个key并将值初始化为0, 并且默认设置key的有效时间为长期.
    这样上面的代码就基本可以限制住访问次数,并在1小时内失效,允许重新访问.

    但是在高并发的情况下,当某进程查询key不存在,所以执行了上面的incr后,会将值初始化为0,
    假如进程1执行了incr, 将key对应的值递增为1,这时在进程1执行 if redis.Redis.get_data(r, key) == 1: 判断前, 进程2也执行了incr,这时key对应的值就会被递增为2, 然后进程1在判断 if redis.Redis.get_data(r, key) == 1: 会发现2 !=1, 所有不会设置过期时间,这样这个访问就会一直被拒绝了.

    解决方法:
    当获取key为None时, 创建key,并直接设置失效时间:

        r = redis.Redis.connect()
        key = "linyk3"
        query_times = redis.Redis.get_data(r, key)
        if not query_times:
            redis.Redis.incr(r, key)
            redis.Redis.expire_data(r, key, 60 * 60)
        elif int(query_times) > 1000:
            print('访问次数过多,超过1000次限制!')
            return 
        else:
            redis.Redis.incr(r, key)
    

    相关文章

      网友评论

        本文标题:Redis 利用 incr 和 expire 来限流, 并发导致

        本文链接:https://www.haomeiwen.com/subject/jmbskqtx.html