Go 语言服务限流算法实现
在分布式系统中,服务限流是一种常见的保护措施,用于防止系统过载和资源耗尽。限流算法可以确保在系统负载过高时,对请求进行合理的控制,从而保证系统的稳定性和可用性。本文将围绕Go语言实现服务限流算法这一主题,详细探讨几种常见的限流算法,并给出相应的代码实现。
限流算法概述
限流算法主要分为以下几类:
1. 固定窗口限流算法:在固定的时间窗口内,限制请求的通过量。
2. 滑动窗口限流算法:在滑动的时间窗口内,限制请求的通过量。
3. 令牌桶算法:通过维护一个令牌桶,按固定速率发放令牌,请求只有在获取到令牌后才能通过。
4. 漏桶算法:通过维护一个漏桶,以固定速率流出水滴,请求以固定速率通过。
固定窗口限流算法
固定窗口限流算法是最简单的限流算法之一。它通过记录每个时间窗口内的请求量来实现限流。
代码实现
go
package main
import (
"fmt"
"time"
)
type FixedWindowLimiter struct {
windowSize time.Duration
requestsPerSec int
requests []int
}
func NewFixedWindowLimiter(windowSize time.Duration, requestsPerSec int) FixedWindowLimiter {
return &FixedWindowLimiter{
windowSize: windowSize,
requestsPerSec: requestsPerSec,
requests: make([]int, 0, int(windowSize.Seconds()/time.Second)),
}
}
func (l FixedWindowLimiter) Allow() bool {
now := time.Now()
windowStart := now.Add(-l.windowSize)
for _, r := range l.requests {
if r >= windowStart.Unix() {
return false
}
}
l.requests = append(l.requests, now.Unix())
if len(l.requests) > int(l.windowSize.Seconds()/time.Second) {
l.requests = l.requests[1:]
}
return true
}
func main() {
limiter := NewFixedWindowLimiter(10time.Second, 100)
for i := 0; i < 200; i++ {
if limiter.Allow() {
fmt.Println("Request allowed")
} else {
fmt.Println("Request denied")
}
time.Sleep(50 time.Millisecond)
}
}
滑动窗口限流算法
滑动窗口限流算法与固定窗口限流算法类似,但它在处理请求时,会滑动窗口,而不是每次都从头开始。
代码实现
go
package main
import (
"fmt"
"time"
)
type SlidingWindowLimiter struct {
windowSize time.Duration
requestsPerSec int
requests []int
}
func NewSlidingWindowLimiter(windowSize time.Duration, requestsPerSec int) SlidingWindowLimiter {
return &SlidingWindowLimiter{
windowSize: windowSize,
requestsPerSec: requestsPerSec,
requests: make([]int, 0, int(windowSize.Seconds()/time.Second)),
}
}
func (l SlidingWindowLimiter) Allow() bool {
now := time.Now()
windowStart := now.Add(-l.windowSize)
for i, r := range l.requests {
if r >= windowStart.Unix() {
if i == 0 {
l.requests = l.requests[1:]
} else {
l.requests[i] = now.Unix()
}
break
}
}
l.requests = append(l.requests, now.Unix())
if len(l.requests) > int(l.windowSize.Seconds()/time.Second) {
l.requests = l.requests[1:]
}
return true
}
func main() {
limiter := NewSlidingWindowLimiter(10time.Second, 100)
for i := 0; i < 200; i++ {
if limiter.Allow() {
fmt.Println("Request allowed")
} else {
fmt.Println("Request denied")
}
time.Sleep(50 time.Millisecond)
}
}
令牌桶算法
令牌桶算法通过维护一个令牌桶,以固定速率发放令牌,请求只有在获取到令牌后才能通过。
代码实现
go
package main
import (
"fmt"
"time"
)
type TokenBucketLimiter struct {
rate float64
capacity int
tokens int
lastTime time.Time
}
func NewTokenBucketLimiter(rate float64, capacity int) TokenBucketLimiter {
return &TokenBucketLimiter{
rate: rate,
capacity: capacity,
tokens: capacity,
lastTime: time.Now(),
}
}
func (l TokenBucketLimiter) Allow() bool {
now := time.Now()
elapsed := now.Sub(l.lastTime).Seconds()
l.tokens += int(elapsed l.rate)
if l.tokens > l.capacity {
l.tokens = l.capacity
}
l.lastTime = now
if l.tokens > 0 {
l.tokens--
return true
}
return false
}
func main() {
limiter := NewTokenBucketLimiter(1, 100)
for i := 0; i < 200; i++ {
if limiter.Allow() {
fmt.Println("Request allowed")
} else {
fmt.Println("Request denied")
}
time.Sleep(10 time.Millisecond)
}
}
漏桶算法
漏桶算法通过维护一个漏桶,以固定速率流出水滴,请求以固定速率通过。
代码实现
go
package main
import (
"fmt"
"time"
)
type BucketLimiter struct {
rate float64
lastTime time.Time
}
func NewBucketLimiter(rate float64) BucketLimiter {
return &BucketLimiter{
rate: rate,
lastTime: time.Now(),
}
}
func (l BucketLimiter) Allow() bool {
now := time.Now()
elapsed := now.Sub(l.lastTime).Seconds()
l.lastTime = now
if elapsed > 1 {
return true
}
return false
}
func main() {
limiter := NewBucketLimiter(1)
for i := 0; i < 200; i++ {
if limiter.Allow() {
fmt.Println("Request allowed")
} else {
fmt.Println("Request denied")
}
time.Sleep(10 time.Millisecond)
}
}
总结
本文介绍了四种常见的限流算法,并给出了Go语言的实现代码。在实际应用中,可以根据具体场景选择合适的限流算法,以达到最佳的性能和效果。
Comments NOTHING