参考书籍:《redis深度历险:核心原理与应用实践》
漏斗限流是最常用的限流方法之一。漏斗的容量代表着规定的行为可以持续的总数量,漏斗的剩余空间就代表着当前行为可以持续进行的数量,漏嘴的流速代表着系统允许该行为的最大频率。
import time class Funnel(object): def __init__(self,capacity,leaking_rate): self.capacity=capacity#l漏斗容量 self.leaking_rate=leaking_rate#漏斗流速 self.left_quota=capacity#漏斗剩余空间 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+=delta_quota#将腾地空间增加到剩余空间 self.leaking_ts=now_ts#记录漏水时间 if self.left_quota>self.capacity:#剩余空间不得高于容量 self.left_quota=self.capacity def watering(self,quota): self.make_space() if self.left_quota>=quota:#判断剩余空间是否充足 self.left_quota-=quota return True return False funnels={} def is_action_allowed(user_id,action_key,capacity,leaking_rate): key='%s:%s'%(user_id,action_key) funnel=funnels.get(key) if not funnel: funnel=Funnel(capacity,leaking_rate) funnels[key]=funnel return funnel.watering(1) for i in range(20): print(is_action_allowed('hello','reply',15,0.5)) time.sleep(1)#因为程序运行速度是很快的,所以运行后你会看到15个True,5个 #False,所以我们这里来sleep一秒来看运行效果。
Funnel对象的make_space方法是漏斗算法的核心,其在每次灌水之前都会被调用以触发漏水,给漏斗腾出空间来。能腾出多少空间取决于过去了多久以及流水的素瘤。Funnel对象占据的空间大小是固定的,是一个常量。