我命由我,不由天!


  • 搜索
prometheus docker golang linux kubernetes

redis-限流(七)

发表于 2021-05-29 | 0 | 阅读次数 329

限流

断尾求生——简单限流

限定用户的某个行为在指定的时间里只能允许发生N次

解决方案

这个限流需求中存在一个滑动时间窗口,用一个zset结构记录用户的行为历史,每一个行为都会作为zset中的一个key保存下来

def is_aciton_allowed(user_id,action_key,period,max_count):
  key = "his:%s:%s"%(user_id,action_key)
  now_ts = int(time.time * 1000)
  with client.pipline() as pipe:
    pipe.zadd(key,now_ts,now_ts)
    pipe.zremrangebyscore(key,0,now_ts-period*1000)
    pipe.zcard(key)
    pipe.expire(key,period+1)
    _,_,current_count,_pipe.execute()
  return current_count <= max_count

缺点

需要记录窗口内所有的行为记录,如果这个量很大,比如60s内操作不得超过100万次,不适合做这样的限流,需要消耗大量的存储空间

一毛不拔——漏斗限流

漏斗限流是最常用的限流方法之一,漏斗的容量是有限的,如果将漏嘴堵住,然后一直往里面灌水,它就会变满,直至装不进。如果漏嘴放开,水就会往下流,流走一部分之后,又可以继续往里面灌水。

所以,漏斗的剩余空间就代表当前行为可以持续进行的数量,漏嘴的流水速率代表着系统允许该行为的最大频率。

漏斗算法

class Funnel(object):
    def __init__(self,capactiy,leaking_rate):
        self.capactiy = capactiy
        self.leaking_rate = leaking_rate
        self.left_quota = capactiy
        self.leaking_ts = time.time()
    
    def make_space(self):
        now_ts = time.time()
        delta_ts = now_ts - self.leaking_ts
        delta_quota = delta_ts * self.leaking_rate
        
        if delta_quota < 1:
            return
        self.left_quota = self.left_quota + delta_quota
        self.leaking_ts = now_ts
        if self.left_quota > self.capactiy:
            self.left_quota = self.capactiy
    
    def watering(self,quota):
        self.make_space()
        if self.left_quota >= quota:
            self.left_quota -= quota
            return True
        return False

Funnel对象的make_space是漏斗算法的核心,每次灌水前都会被调用以触发漏水,给漏斗腾出空间。能腾出多少空间取决于过去了多久以及流水的速率。

Redis-Cell

一个限流Redis模块,使用了漏斗算法

image.png

  • 本文作者: Dante
  • 本文链接: https://gaodongfei.com/archives/redis-限流
  • 版权声明: 本博客所有文章除特别声明外,均采用CC BY-NC-SA 3.0 许可协议。转载请注明出处!
redis-布隆过滤器(六)
redis-GeoHash(八)
  • 文章目录
  • 站点概览
Dante

Dante

119 日志
5 分类
5 标签
RSS
Creative Commons
0%
© 2023 Dante
由 Halo 强力驱动
|
主题 - NexT.Pisces v5.1.4
沪ICP备2020033702号