Redis 利用 incr 和 expire 来限流, 并发导致过期时间失效问题

当某一个接口需要限流时,可以采用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)
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

  • NOSQL类型简介键值对:会使用到一个哈希表,表中有一个特定的键和一个指针指向特定的数据,如redis,volde...
    MicoCube阅读 9,499评论 2 27
  • 超强、超详细Redis入门教程 转载2017年03月04日 16:20:02 16916 转载自: http://...
    邵云涛阅读 17,567评论 3 313
  • 1.什么是redis? Redis 是一个基于内存的高性能key-value数据库。 2.Reids的特点 Red...
    java成功之路阅读 3,114评论 0 8
  • 【本教程目录】 1.redis是什么2.redis的作者3.谁在使用redis4.学会安装redis5.学会启动r...
    徐猿猿阅读 5,828评论 0 35
  • 一一祝贺中国十九大会议热烈召开 雄狮已醒 活跃着矫健的身影 在世界的舞台上跳跃狂奔 正在冲刺着世界的最高脊梁和峰顶...
    王小永_6be2阅读 1,391评论 0 5

友情链接更多精彩内容