返回
基于滑动时间窗口的「预热桶」限流算法揭秘
前端
2023-09-24 20:26:23
现代分布式系统中,QPS (每秒查询数) 是一个重要的性能指标。它衡量了系统每秒能够处理的请求数量。当请求量超过系统所能承受的阈值时,系统就会出现拥塞,导致性能下降,甚至崩溃。
限流是一种保护系统免受过载的常用技术。它通过限制每秒允许进入系统的请求数量,来防止系统被过多的请求压垮。
「预热桶」限流算法是一种基于滑动时间窗口的限流算法。它将时间划分为一个个固定大小的窗口,并在每个窗口内允许一定数量的请求通过。当窗口内的请求数量达到阈值时,超过阈值的请求就会被拒绝。
「预热桶」限流算法的主要优点是,它可以动态调整限流阈值,以适应系统流量的变化。当系统流量较低时,限流阈值可以调高,以允许更多的请求通过。当系统流量较高时,限流阈值可以调低,以防止系统过载。
算法原理
「预热桶」限流算法的工作原理如下:
- 将时间划分为一个个固定大小的窗口,窗口的大小通常为 1 秒或 1 分钟。
- 在每个窗口内,允许一定数量的请求通过。这个数量称为「预热桶」容量。
- 当窗口内的请求数量达到「预热桶」容量时,超过容量的请求就会被拒绝。
- 每个窗口都有一个滑动时间窗口。当窗口到期时,窗口内的所有请求都会被清除,并且「预热桶」容量会重置。
Go语言实现
package main
import (
"fmt"
"sync"
"time"
)
type PrewarmBucket struct {
// 预热桶容量
capacity int
// 滑动时间窗口大小
windowSize time.Duration
// 当前窗口内已处理的请求数
currentCount int
// 上一个窗口内已处理的请求数
previousCount int
// 滑动时间窗口的开始时间
startTime time.Time
// 互斥锁,用于保护并发访问
mu sync.Mutex
}
func NewPrewarmBucket(capacity int, windowSize time.Duration) *PrewarmBucket {
return &PrewarmBucket{
capacity: capacity,
windowSize: windowSize,
startTime: time.Now(),
currentCount: 0,
previousCount: 0,
}
}
// 允许一个请求通过
func (b *PrewarmBucket) Allow() bool {
b.mu.Lock()
defer b.mu.Unlock()
// 检查当前窗口是否已满
if b.currentCount >= b.capacity {
return false
}
// 更新当前窗口内已处理的请求数
b.currentCount++
// 检查滑动时间窗口是否已到期
if time.Since(b.startTime) >= b.windowSize {
// 重置滑动时间窗口
b.startTime = time.Now()
// 将上一个窗口内已处理的请求数设置为当前窗口内已处理的请求数
b.previousCount = b.currentCount
// 重置当前窗口内已处理的请求数
b.currentCount = 0
}
return true
}
func main() {
// 创建一个预热桶限流器,容量为 100,滑动时间窗口大小为 1 秒
limiter := NewPrewarmBucket(100, time.Second)
// 模拟 1000 个请求
for i := 0; i < 1000; i++ {
// 尝试允许一个请求通过
if limiter.Allow() {
// 请求通过,处理请求
fmt.Println("请求", i, "通过")
} else {
// 请求被拒绝,返回错误
fmt.Println("请求", i, "被拒绝")
}
}
}
结语
「预热桶」限流算法是一种简单高效的限流算法。它易于实现,并且可以动态调整限流阈值,以适应系统流量的变化。在分布式系统中,它是一种常用的限流算法。