【go从零单排】Rate Limiting限流
🌈Don’t worry , just coding!
内耗与overthinking只会削弱你的精力,虚度你的光阴,每天迈出一小步,回头时发现已经走了很远。
📗概念
在 Go 中,速率限制(Rate Limiting)是一种控制请求速率的技术,通常用于防止过载、保护资源或实现公平访问。速率限制可以通过多种方式实现,包括使用通道、定时器和其他同步原语。
💻代码
通道限流
使用通道速率限制:代码使用了两种速率限制机制。
第一部分通过定时器限制请求的处理频率,第二部分允许在短时间内处理多个请求(突发请求),但仍然会受到后续请求的限制。
package main
import (
"fmt"
"time"
)
func main() {
// 创建一个缓冲通道 requests,容量为 5
requests := make(chan int, 5)
for i := 1; i <= 5; i++ {
requests <- i // 向通道中发送请求
}
close(requests) // 关闭通道
// 创建一个定时器,每 200 毫秒发出一次信号
limiter := time.Tick(200 * time.Millisecond)
// 处理请求
for req := range requests {
<-limiter // 等待定时器信号
fmt.Println("request", req, time.Now()) // 输出请求和当前时间
}
// 创建一个用于突发请求的通道,容量为 3
burstyLimiter := make(chan time.Time, 3)
// 初始填充突发通道
for i := 0; i < 3; i++ {
burstyLimiter <- time.Now() // 向通道中发送当前时间
}
// 启动一个 goroutine,不断向 burstyLimiter 发送时间
go func() {
for t := range time.Tick(200 * time.Millisecond) {
burstyLimiter <- t // 每 200 毫秒向通道中发送时间
}
}()
// 创建一个缓冲通道 burstyRequests,容量为 5
burstyRequests := make(chan int, 5)
for i := 1; i <= 5; i++ {
burstyRequests <- i // 向通道中发送请求
}
close(burstyRequests) // 关闭通道
// 处理突发请求
for req := range burstyRequests {
<-burstyLimiter // 等待从 burstyLimiter 中取出时间
fmt.Println("request", req, time.Now()) // 输出请求和当前时间
}
}
Token Bucket 算法
Token Bucket 算法允许突发流量,但会限制长期的请求速率。每个请求消耗一个令牌,令牌以固定速率生成。
package main
import (
"fmt"
"time"
)
func main() {
// 创建一个通道作为令牌桶
tokenBucket := make(chan struct{}, 3) // 最多 3 个令牌
// 启动一个 goroutine 生成令牌
go func() {
for {
tokenBucket <- struct{}{} // 每 200 毫秒放入一个令牌
time.Sleep(200 * time.Millisecond)
}
}()
// 处理请求
for i := 1; i <= 10; i++ {
<-tokenBucket // 等待获取令牌
fmt.Println("Request", i, "at", time.Now())
}
}
Leaky Bucket 算法
Leaky Bucket 算法是另一种速率限制方法,允许请求以固定速率流出。请求被放入一个“桶”中,如果桶满了,则新请求会被丢弃。
package main
import (
"fmt"
"time"
)
func main() {
// 创建一个通道作为桶
bucket := make(chan struct{}, 3) // 桶的容量为 3
// 启动一个 goroutine 持续从桶中流出
go func() {
for {
time.Sleep(200 * time.Millisecond) // 每 200 毫秒流出一个请求
select {
case <-bucket:
// 从桶中流出
default:
// 桶为空,什么也不做
}
}
}()
// 处理请求
for i := 1; i <= 10; i++ {
select {
case bucket <- struct{}{}: // 尝试将请求放入桶中
fmt.Println("Request", i, "at", time.Now())
default:
fmt.Println("Request", i, "dropped at", time.Now())
}
time.Sleep(100 * time.Millisecond) // 模拟请求间隔
}
}
🔍理解
- 速率限制 是控制请求频率的重要手段,能够有效防止系统过载。
- 基于通道的实现 简单易用,适合基本的速率限制。
- Token Bucket 和 Leaky Bucket 算法 提供了更灵活的速率控制,适合复杂的应用场景。
Go 的并发特性使得实现这些算法变得简单和高效。通过 goroutine 和通道,可以轻松地管理并发请求和速率限制。
目前对go的理解还不能很好的理解到限流的强大,还需继续努力💪
💪无人扶我青云志,我自踏雪至山巅。