请求限流是一种常见的应用场景,即限制在一定时间内某个接口或服务的请求次数或并发数,以保证系统稳定性和性能。下面我们以Golang为例,介绍如何实现请求限流,主要包括两种方式:计数器法和漏桶算法。
1. 计数器法
计数器法是最简单的请求限流算法,原理是统计在一定时间内某个操作的请求次数,如果超过事先设定的阈值,则拒绝新的请求。下面是一个使用计数器法来限流的例子:
package main
import (
"fmt"
"sync"
"time"
)
type Counter struct {
count int // 统计请求数
mutex sync.Mutex // 互斥锁
}
func (c *Counter) Incr() {
c.mutex.Lock()
defer c.mutex.Unlock()
c.count++
}
func (c *Counter) Check(max int) bool {
c.mutex.Lock()
defer c.mutex.Unlock()
if c.count > max {
return false
}
return true
}
func main() {
counter := Counter{}
max := 100 // 最大请求数
duration := time.Second // 统计周期
t1 := time.Now()
go func() {
for {
if counter.Check(max) {
time.Sleep(time.Millisecond * 10) // 模拟请求处理时间
counter.Incr()
} else {
fmt.Println("too many requests")
}
}
}()
for {
fmt.Println(counter.count)
time.Sleep(time.Second)
if time.Since(t1) > duration {
counter.count = 0
t1 = time.Now()
fmt.Println("reset count")
}
}
}
代码解释:
– Counter:封装请求数计数器,实现两个方法,Incr()增加请求数,Check()检查请求数是否超过最大数量;
– main函数:启动一个协程,不断发起请求,每次请求时先检查请求数是否超限,如果没有则处理请求,否则输出“too many requests”;同时,定时输出请求数并重置计数器。
2. 漏桶算法
漏桶算法是另一种流量控制算法,主要思想是将请求按照固定的速率处理,多余的请求会被放入漏桶中,而漏桶有一个固定的容量,如果漏桶已满,新请求将被拒绝。下面是一个使用漏桶算法来限流的例子:
package main
import (
"fmt"
"sync"
"time"
)
type LeakyBucket struct {
capacity int // 桶容量
rate int // 固定流速
water int // 当前水位
lastLeakMs int64 // 上次漏水时间
mutex sync.Mutex
}
func (b *LeakyBucket) Pour(inflow int) bool {
b.mutex.Lock()
defer b.mutex.Unlock()
now := time.Now().UnixNano() / int64(time.Millisecond)
if (now - b.lastLeakMs) > int64(time.Second) {
b.water = 0
b.lastLeakMs = now
}
b.water += inflow
if b.water > b.capacity {
return false
}
b.water -= b.rate
return true
}
func main() {
bucket := LeakyBucket{capacity: 200, rate: 20}
inflow := 30 // 请求流量
duration := time.Second // 统计周期
t1 := time.Now()
go func() {
for {
if bucket.Pour(inflow) {
time.Sleep(time.Millisecond * 10) // 模拟请求处理时间
} else {
fmt.Println("too many requests")
}
}
}()
for {
fmt.Println(bucket.water)
time.Sleep(time.Second)
if time.Since(t1) > duration {
t1 = time.Now()
fmt.Println("reset bucket")
}
}
}
代码解释:
– LeakyBucket:封装漏桶,实现Pour()方法处理请求,同时做漏水处理;
– main函数:启动一个协程,不断发起请求,每次请求时调用Pour()方法处理,如果无法处理则输出“too many requests”;同时,定时输出漏桶水位并重置漏桶。