漏斗限流是最常用的限流方法之一,顾名思义,这个算法的灵感源于漏斗( funnel)的结构。
漏斗的容量是有限的,如果将漏嘴堵住,然后一直往里面灌水,它就会变满,直至再也装不进去。如果将漏嘴放开,水就会往下流,流走一部分之后,就又可以继续往里面灌水。如果漏嘴流水的速率大于灌水的速率,那么漏斗永远都装不满。如果漏嘴流水速率小于灌水的速率,那么一旦漏斗满了,灌水就需要暂停并等待漏斗腾出一部分空间。
...
public class FunnelRateLimiter {
static class Funnel {
int capacity;
float leakingRate;
int leftQuota;
long leakingTs;
public Funnel(int capac 工 ty , float leakingRate) {
this.capacity = capacity ;
this.leakingRate = leakingRate;
this .leftQuota = capacity;
this . leakingTs = System.currentTimeM工 llis () ;
飞roid makeSpace () {
long nowTs = System . currentTimeMill 工 s () ;
lo口g deltaTs = nowTs - leakingTs;
int deltaQuota = (int) (deltaTs * leakingRate) ;
// 间隔时间太长 ,整数数字过大溢 出
if (deltaQuota < 0) {
this . leftQuota =capacity ;
this.leakingTs = nowTs;
return;
//腾出空间太小 ,最小单位是 l
if (deltaQuota < 1) {
return ·
this.leftQuota += deltaQuota ;
this.leakingTs = nowTs ;
if (this. leftQuota > this . capacity) {
this.leftQuota = this . capacity;
boolean watering(int quota) {
makeSpace() ;
if (this . leftQuota >= quota) {
this.leftQuota - = quota;
return true;
return false;
private Map<String, Funnel> funnels =new HashMap<>() ;
public boolean isActionAllowed(String userld, String actionKey,
int capacity , float leakingRate) {
String key= String . format ( ” 宅 s : 毡 s ”, user i d , act 工 onKey );
Fu nne l funne l = funnels . get (key );
工 f (funnel == null) {
funnel= new Funnel(capacity, lea k工ngRate) ;
funne l s . put(key , funnel);
return funnel.watering(l); //需妥 1 个 quota
}
}
...
分布式漏斗限流 redis-cell
cl. throttle zzy : reply 15 30 60 1
need 1 quota (可选参鼓,默认值也是1)
30 operations / 60 seconds 这是漏水速率
15 capacity 这是漏斗容量
key zzy
cl.throttle zzy : reply 15 30 60
- (integer) 0 # 0 表示允许, 1 表示拒绝
- (integer) 15 #漏斗容量 capacity
3)(integer) 14 #漏斗剩余空间 left quota - (integer) -1 #如采被拒绝了,需要多长时间后再试(漏斗有空间了,单位秒)
- (integer) 2 #多长时间后,漏斗完全空出来( left quota==capacity,单位秒)