zoukankan      html  css  js  c++  java
  • 从今天开始看《Redis深度历险》 -- 简单限流

    限流问题是分布式系统中无论如何都绕不开的一个话题,缓存穿透、缓存击穿、缓存雪崩这几个问题也是避不开的,这一篇就学习一下如何使用redis实现一个简单的限流。

      限流不仅仅是控制流量,还有一点就是控制用户行为,一些很明显的非法请求(比如高并发的爬虫),就得制定相应的策略来处理。

      限流的思路容易想到的一点就是限制请求频率,在一定时间内的请求次数过多就进行限制。这点容易想到的原因就是爬虫的时候会被限制IP,一部分原因也就是请求太过频繁就会被检测到异常(想起来当初用自己的账号爬某宝,结果后来用的时候点一下跳出一次验证码。。)。但是到底使用啥结构来实现呢?作者提出的思路是使用zset。

      这种场景需要一个时间窗口来查看用户在这段时间内的请求次数,如果我们将时间作为zset的score,那么就可以直接查询指定score区间内的值的数量是否超过限制。

    python版代码如下:

    import time
    import redis
    
    
    client = redis.StrictRedis()
    
    def is_action_allowed(user_id, action_key, period, max_count):
    	key = f'hist:{user_id}:{action_key}'
    	# 使用毫秒时间戳
    	now_ts = int(time.time()*1000)
    	with client.pipeline() as pipe:
    		# 记录行为, score和value都使用时间戳
    		pipe.zadd(key, now_ts, now_ts)
    		# 移除窗口时间之外的请求
    		pipe.zremrangebyscore(key, 0, now_ts-period*1000)
    		pipe.zcard(key)
    		# 设置zset的过期时间,避免冷用户持续占用内存
    		# 过期时间应该等于时间窗口长度,多宽限出1S
    		pipe.expire(key, period + 1)
    		# 批量执行
    		_, _, current_count, _ = pipe.execute()
    	# 比较数量是否超标
    	return current_count <= max_count
    
    for i in range(20):
    	print(is_action_allowed('user_id', 'action', 60, 5))
    

      这段代码的整体思路其实并不复杂,每次进行判断的时候都维护一次对应user的时间窗口,窗口外的记录都清除,我们判断的依据是score,因此score的值是很重要的,value的值就没有什么特别的意义。

      文中指出该中种方式的连续几个操作都是针对同一个key的,使用pipeline可以大大提高效率。但是这种方式的缺点也是很明显的,如果单位时间内的允许的请求次数非常高的话,将会浪费大量的内存,因此这种方法的局限性很大。后文中将继续介绍其他几种限流方案。

  • 相关阅读:
    hdu 4027 Can you answer these queries?
    Codeforces: Empty Triangle
    hdu 3006 The Number of set
    hdu 3645 Code Management System
    进度条作控件代码
    NORMAL
    callback
    三种形状匹配脚本
    移动点动画
    脚本管理
  • 原文地址:https://www.cnblogs.com/slientbrain/p/13048372.html
Copyright © 2011-2022 走看看