Open kevinyan815 opened 3 years ago
计数器是一种比较简单粗暴的限流算法,其思想是在固定时间窗口内对请求进行计数,与阀值进行比较判断是否需要限流,一旦到了时间临界点,将计数器清零。
计数器算法存在“时间临界点”缺陷。比如每一分钟限制100个请求,可以在00:00:00-00:00:58秒里面都没有请求,在00:00:59瞬间发送100个请求,这个对于计数器算法来是允许的,然后在00:01:00再次发送100个请求,意味着在短短1s内发送了200个请求,如果量更大呢,系统可能会承受不住瞬间流量,导致系统崩溃。(如下图所示)
所以计数器算法实现限流的问题是没有办法应对突发流量。
type LimitRate struct { rate int //阀值 begin time.Time //计数开始时间 cycle time.Duration //计数周期 count int //收到的请求数 lock sync.Mutex //锁 } func (limit *LimitRate) Allow() bool { limit.lock.Lock() defer limit.lock.Unlock() // 判断收到请求数是否达到阀值 if limit.count == limit.rate-1 { now := time.Now() // 达到阀值后,判断是否是请求周期内 if now.Sub(limit.begin) >= limit.cycle { limit.Reset(now) return true } return false } else { limit.count++ return true } } func (limit *LimitRate) Set(rate int, cycle time.Duration) { limit.rate = rate limit.begin = time.Now() limit.cycle = cycle limit.count = 0 } func (limit *LimitRate) Reset(begin time.Time) { limit.begin = begin limit.count = 0 }
算法思想
计数器是一种比较简单粗暴的限流算法,其思想是在固定时间窗口内对请求进行计数,与阀值进行比较判断是否需要限流,一旦到了时间临界点,将计数器清零。
面临的问题
计数器算法存在“时间临界点”缺陷。比如每一分钟限制100个请求,可以在00:00:00-00:00:58秒里面都没有请求,在00:00:59瞬间发送100个请求,这个对于计数器算法来是允许的,然后在00:01:00再次发送100个请求,意味着在短短1s内发送了200个请求,如果量更大呢,系统可能会承受不住瞬间流量,导致系统崩溃。(如下图所示)
所以计数器算法实现限流的问题是没有办法应对突发流量。
Go代码实现