美文网首页思科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