当某一个接口需要限流时,可以采用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)