固定窗口
package main
import (
"fmt"
"sync"
"sync/atomic"
"time"
)
type RateLimiter struct {
interval time.Duration
tokens int32
lastTime int64
mu sync.Mutex
}
func NewRateLimiter(interval time.Duration, tokens int32) *RateLimiter {
return &RateLimiter{
interval: interval,
tokens: tokens,
lastTime: time.Now().UnixNano(),
}
}
func (l *RateLimiter) TryAcquire() bool {
l.mu.Lock()
defer l.mu.Unlock()
now := time.Now().UnixNano()
elapsed := now - l.lastTime
l.lastTime = now
l.tokens += elapsed / int64(l.interval)
if l.tokens < 1 {
return false
}
l.tokens--
return true
}
func main() {
limiter := NewRateLimiter(time.Second, 10)
var wg sync.WaitGroup
wg.Add(50)
for i := 0; i < 50; i++ {
go func() {
defer wg.Done()
if limiter.TryAcquire() {
fmt.Println("请求被处理")
} else {
fmt.Println("请求被限流")
}
}()
}
wg.Wait()
}
计数器
package main
import (
"fmt"
"sync"
"time"
)
type CountLimiter struct {
rate int64
begin time.Time
count int64
cycle time.Duration
lock sync.Mutex
}
func NewCountLimiter(rate int64, cycle time.Duration) *CountLimiter {
return &CountLimiter{
rate: rate,
begin: time.Now(),
count: 0,
cycle: cycle,
lock: sync.Mutex{},
}
}
func (c *CountLimiter) Allow() bool {
c.lock.Lock()
defer c.lock.Unlock()
if c.count == c.rate {
if time.Now().Sub(c.begin) > c.cycle {
c.Reset()
return true
} else {
return false
}
} else {
c.count++
return true
}
}
func (c *CountLimiter) Reset() {
c.begin = time.Now()
c.count = 0
}
func main() {
countLimiter := NewCountLimiter(3, time.Second)
var wg sync.WaitGroup
wg.Add(10)
for i := 0; i < 10; i++ {
go func(i int) {
defer wg.Done()
if countLimiter.Allow() {
fmt.Println(fmt.Sprintf("当前时间%s,请求%d通过了", time.Now().String(), i))
} else {
fmt.Println(fmt.Sprintf("当前时间%s,请求%d被限流了", time.Now().String(), i))
}
}(i)
time.Sleep(200 * time.Millisecond)
}
wg.Wait()
}
令牌桶
package main
import (
"fmt"
"sync"
"time"
)
type TokenBucketLimiter struct {
lock sync.Mutex
rate time.Duration
capacity int64
tokens int64
lastTime time.Time
}
func NewTokenBucketLimiter(rate time.Duration, capacity int64) *TokenBucketLimiter {
if capacity < 1 {
panic("token bucket capacity must be large 1")
}
return &TokenBucketLimiter{
lock: sync.Mutex{},
rate: rate,
capacity: capacity,
tokens: 0,
lastTime: time.Time{},
}
}
func (tbl *TokenBucketLimiter) Allow() bool {
tbl.lock.Lock()
defer tbl.lock.Unlock()
now := time.Now()
if now.Sub(tbl.lastTime) > tbl.rate {
tbl.tokens += int64((now.Sub(tbl.lastTime)) / tbl.rate)
if tbl.tokens > tbl.capacity {
tbl.tokens = tbl.capacity
}
tbl.lastTime = now
}
if tbl.tokens > 0 {
tbl.tokens -= 1
return true
}
return false
}
func main() {
tbl := NewTokenBucketLimiter(10, 5)
for i := 0; i < 10; i++ {
fmt.Println(tbl.Allow())
}
time.Sleep(100 * time.Millisecond)
fmt.Println(tbl.Allow())
}
漏斗
package main
import (
"context"
"fmt"
"sync"
"time"
)
type Result struct {
Msg string
}
type Handler func() Result
type Task struct {
id int64
result chan Result
handler Handler
}
func NewTask(id int, handler Handler) Task {
return Task{
handler: handler,
result: make(chan Result),
id: int64(id),
}
}
type LeakyBucketLimiter struct {
bucketSize int64
workerNum int64
taskChan chan Task
}
func NewLeakyBucketLimiter(bucketSize, workerNum int64) *LeakyBucketLimiter {
if capacity < 1 {
panic("capacity must be large 1")
}
if workerNum < 1 {
panic("workerNum must be large 1")
}
return &LeakyBucketLimiter{
bucketSize: bucketSize,
workerNum: workerNum,
taskChan: make(chan Task, bucketSize),
}
}
func (lbl *LeakyBucketLimiter) AddTask(task Task) bool {
select {
case lbl.taskChan <- task:
default:
fmt.Printf("请求%d被拒绝了\n", task.id)
return false
}
select {
case resp := <-task.result:
fmt.Printf("请求%d运行成功,结果为:%v\n", task.id, resp)
case <-time.After(5 * time.Second):
return false
}
return true
}
func (lbl *LeakyBucketLimiter) Start(ctx context.Context) {
for i := 0; int64(i) < lbl.workerNum; i++ {
go func(ctx context.Context) {
defer func() {
if err := recover(); err != any(nil) {
fmt.Println("捕获到异常")
}
}()
for {
select {
case <-ctx.Done():
fmt.Println("退出工作")
return
default:
task := <-lbl.taskChan
result := task.handler()
task.result <- result
}
}
}(ctx)
}
}
func main() {
bucket := NewLeakyBucketLimiter(10, 4)
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
bucket.Start(ctx)
var wg sync.WaitGroup
wg.Add(20)
for i := 0; i < 20; i++ {
go func(id int) {
defer wg.Done()
task := NewTask(id, func() Result {
time.Sleep(300 * time.Millisecond)
return Result{}
})
bucket.AddTask(task)
}(i)
}
wg.Wait()
time.Sleep(10 * time.Second)
}
滑动窗口
package main
import (
"errors"
"sync"
"time"
)
type SlidingWindowLimiter struct {
limit int
window int64
smallWindow int64
smallWindows int64
counters map[int64]int
mutex sync.RWMutex
}
func NewSlidingWindowLimiter(limit int, window, smallWindow time.Duration) (*SlidingWindowLimiter, error) {
if int64(window%smallWindow) != 0 {
return nil, errors.New("window size must be divisible by the small window size")
}
return &SlidingWindowLimiter{
limit: limit,
window: int64(window),
smallWindow: int64(smallWindow),
smallWindows: int64(window / smallWindow),
counters: make(map[int64]int),
}, nil
}
func (l *SlidingWindowLimiter) TryAcquire() bool {
l.mutex.RLock()
defer l.mutex.RUnlock()
now := time.Now().UnixNano()
currentSmallWindow := now / l.smallWindow * l.smallWindow
l.cleanExpiredWindows(now)
l.mutex.Lock()
defer l.mutex.Unlock()
count, exists := l.counters[currentSmallWindow]
if !exists || count < l.limit {
l.counters[currentSmallWindow] = count + 1
return true
}
return false
}
func (l *SlidingWindowLimiter) cleanExpiredWindows(now int64) {
startSmallWindow := now/l.smallWindow*l.smallWindow - l.window
for smallWindow := range l.counters {
if smallWindow < startSmallWindow {
delete(l.counters, smallWindow)
}
}
}
func main() {
limiter, err := limiter.NewSlidingWindowLimiter(5, 10*time.Second, time.Second)
if err != nil {
fmt.Println("Error creating limiter:", err)
return
}
for i := 0; i < 10; i++ {
if limiter.TryAcquire() {
fmt.Println("Request", i+1, "allowed")
} else {
fmt.Println("Request", i+1, "denied")
}
time.Sleep(100 * time.Millisecond)
}
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 【自荐】一款简洁、开源的在线白板工具 Drawnix
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· Docker 太简单,K8s 太复杂?w7panel 让容器管理更轻松!