固定窗口速率限制:在这种方法中,速率限制在固定的时间窗口内强制执行。例如,如果速率限制设置为每分钟100个请求,系统将在任何给定的60秒窗口中允许最多100个请求。超过此限制的请求将被拒绝或延迟到下一个时间窗口。
令牌桶速率限制:令牌桶速率限制是基于从一个桶中消耗令牌的概念。桶最初由固定数量的令牌填充,每个令牌代表一个请求。当客户端想要发出请求时,它必须从桶中获取令牌。如果桶为空,客户端必须等待,直到令牌可用。
func fixedWindowRateLimiting() { limiter := rate.NewLimiter(rate.Limit(100), 1) // 允许每秒100次 for i := 0; i < 200; i++ { if !limiter.Allow() { fmt.Println("Rate limit exceeded. Request rejected.") continue } go process() } } // 堆代码 duidaima.com // 处理请求 func process() { fmt.Println("Request processed successfully.") time.Sleep(time.Millisecond) // 模拟请求处理时间 }在上面的代码片段中,我们创建了一个限制使用率。速率限制为每秒100个请求的NewLimiter。对每个请求调用limiter.Allow()方法,如果允许请求,则返回true;如果超过速率限制,则返回false。如果超过速率限制,请求将被拒绝。
Request processed successfully. Rate limit exceeded. Request rejected. Rate limit exceeded. Request rejected. Rate limit exceeded. Request rejected. Rate limit exceeded. Request rejected. Rate limit exceeded. Request rejected. Rate limit exceeded. Request rejected. Rate limit exceeded. Request rejected. ...
func tokenBucketRateLimiting() { limiter := rate.NewLimiter(rate.Limit(10), 5) ctx, _ := context.WithTimeout(context.TODO(), time.Millisecond) for i := 0; i < 200; i++ { if err := limiter.Wait(ctx); err != nil { fmt.Println("Rate limit exceeded. Request rejected.") continue } go process() } } // 处理请求 func process() { fmt.Println("Request processed successfully.") time.Sleep(time.Millisecond) // 模拟请求处理时间 }在上述代码中,我们使用 rate.NewLimiter 创建了一个限制器,其速率限制为每秒 10 个请求,突发 5 个请求。每个请求都会调用 limiter.Wait() 方法,该方法会阻塞直到有令牌可用。如果水桶是空的,没有可用的令牌,请求就会被拒绝。
Request processed successfully. Rate limit exceeded. Request rejected. Rate limit exceeded. Request rejected. Request processed successfully. Rate limit exceeded. Request rejected.
func dynamicRateLimiting() { limiter := rate.NewLimiter(rate.Limit(10), 1) // 允许每秒100次 // Dynamic rate adjustment go func() { time.Sleep(time.Second * 10) // 每10秒调整 limiter fmt.Println("---adjust limiter---") limiter.SetLimit(rate.Limit(200)) // 将 limiter 提升到每秒 200 }() for i := 0; i < 3000; i++ { if !limiter.Allow() { fmt.Println("Rate limit exceeded. Request rejected.") time.Sleep(time.Millisecond * 100) continue } process() } } // 处理请求 func process() { fmt.Println("Request processed successfully.") time.Sleep(time.Millisecond * 10) // 模拟请求处理时间 }在上面的代码片段中,我们创建了一个限制器,初始速率限制为每秒 10 个请求。然后,我们启动一个 goroutine,在 10秒钟后将速率限制调整为每秒 200 个请求。这样,我们就能根据不断变化的情况动态调整速率限制。
... Request processed successfully. Rate limit exceeded. Request rejected. Request processed successfully. ---adjust limiter--- Rate limit exceeded. Request rejected. Request processed successfully. Request processed successfully. Request processed successfully. Request processed successfully. Request processed successfully. ...自适应速率限制
func adaptiveRateLimiting() { limiter := rate.NewLimiter(rate.Limit(10), 1) // 允许每秒10次 // 自适应调整 go func() { for { time.Sleep(time.Second * 10) responseTime := measureResponseTime() // 测量之前请求的响应时间 if responseTime > 500*time.Millisecond { fmt.Println("---adjust limiter 50---") limiter.SetLimit(rate.Limit(50)) } else { fmt.Println("---adjust limiter 100---") limiter.SetLimit(rate.Limit(100)) } } }() for i := 0; i < 3000; i++ { if !limiter.Allow() { fmt.Println("Rate limit exceeded. Request rejected.") time.Sleep(time.Millisecond * 100) continue } process() } } // 测量以前请求的响应时间 // 执行自己的逻辑来测量响应时间 func measureResponseTime() time.Duration { return time.Millisecond * 100 } // 处理请求 func process() { fmt.Println("Request processed successfully.") time.Sleep(time.Millisecond * 10) // 模拟请求处理时间 }在上述代码片段中,我们使用 measureResponseTime 函数模拟测量之前请求的响应时间。根据测量到的响应时间,我们通过使用 limiter.SetLimit 设置不同的值来动态调整速率限制。这样,系统就能根据观察到的响应时间调整其速率限制策略。
Request processed successfully. Rate limit exceeded. Request rejected. Request processed successfully. Rate limit exceeded. Request rejected. ---adjust limiter 100--- Request processed successfully. Request processed successfully. Request processed successfully. Request processed successfully. Request processed successfully.