发布时间:2024-12-22 23:58:21
在高并发的系统中,经常需要对接口进行限流,以避免系统崩溃或过载。Golang提供了很多实现限流的方法,本文将介绍一些常用的方法。
固定窗口计数器算法是一种简单直观的限流算法。它基于滑动窗口的思想,将一段时间分成固定大小的窗口,在每个窗口内设置一个计数器,记录请求的次数。当请求到来时,如果计数器的值超过了设定的阈值,则拒绝请求。
以下是一个使用Golang实现的固定窗口计数器算法的示例:
package main
import (
"fmt"
"time"
)
type FixedWindowLimiter struct {
windowSize int
maxRequest int
requestCounter int
requestTime []int64
}
func NewFixedWindowLimiter(windowSize, maxRequest int) *FixedWindowLimiter {
return &FixedWindowLimiter{
windowSize: windowSize,
maxRequest: maxRequest,
requestCounter: 0,
requestTime: make([]int64, 0),
}
}
func (limiter *FixedWindowLimiter) AllowRequest() bool {
now := time.Now().Unix()
limiter.requestTime = append(limiter.requestTime, now)
limiter.requestCounter++
if len(limiter.requestTime) > limiter.maxRequest {
oldestRequestTime := limiter.requestTime[0]
if now-oldestRequestTime < int64(limiter.windowSize) {
return false
}
limiter.requestTime = limiter.requestTime[1:]
limiter.requestCounter--
}
return true
}
func main() {
limiter := NewFixedWindowLimiter(10, 100)
for i := 0; i < 200; i++ {
if limiter.AllowRequest() {
fmt.Println("Allow")
} else {
fmt.Println("Reject")
}
time.Sleep(100 * time.Millisecond)
}
}
漏斗算法是一种比较适用于平滑限流的算法。它模拟了一个漏斗,在漏斗中的水以固定的速率流出,当请求到来时,如果漏斗还有剩余容量,则允许通过。
以下是一个使用Golang实现的漏斗算法的示例:
package main
import (
"fmt"
"time"
)
type LeakyBucketLimiter struct {
rate float64
capacity int
waterLevel int
lastLeakTime int64
}
func NewLeakyBucketLimiter(rate float64, capacity int) *LeakyBucketLimiter {
return &LeakyBucketLimiter{
rate: rate,
capacity: capacity,
waterLevel: 0,
lastLeakTime: time.Now().Unix(),
}
}
func (limiter *LeakyBucketLimiter) AllowRequest() bool {
now := time.Now().Unix()
elapsedTime := now - limiter.lastLeakTime
leakedWater := int(float64(elapsedTime) * limiter.rate)
if leakedWater > 0 {
if leakedWater > limiter.waterLevel {
limiter.waterLevel = 0
} else {
limiter.waterLevel -= leakedWater
}
limiter.lastLeakTime = now
}
if limiter.waterLevel < limiter.capacity {
limiter.waterLevel++
return true
} else {
return false
}
}
func main() {
limiter := NewLeakyBucketLimiter(0.5, 10)
for i := 0; i < 20; i++ {
if limiter.AllowRequest() {
fmt.Println("Allow")
} else {
fmt.Println("Reject")
}
time.Sleep(100 * time.Millisecond)
}
}
令牌桶算法是一种广泛应用于限流场景的算法。它维护了一个桶,桶中存放着令牌。当请求到来时,如果桶中有令牌,则允许通过,并消耗一个令牌;如果桶中没有令牌,则拒绝请求。
以下是一个使用Golang实现的令牌桶算法的示例:
package main
import (
"fmt"
"time"
)
type TokenBucketLimiter struct {
rate float64
capacity int
tokens int
lastRefillTime int64
}
func NewTokenBucketLimiter(rate float64, capacity int) *TokenBucketLimiter {
return &TokenBucketLimiter{
rate: rate,
capacity: capacity,
tokens: capacity,
lastRefillTime: time.Now().Unix(),
}
}
func (limiter *TokenBucketLimiter) AllowRequest() bool {
now := time.Now().Unix()
elapsedSeconds := now - limiter.lastRefillTime
refillAmount := int(float64(elapsedSeconds) * limiter.rate)
if refillAmount > 0 {
if limiter.tokens+refillAmount > limiter.capacity {
limiter.tokens = limiter.capacity
} else {
limiter.tokens += refillAmount
}
limiter.lastRefillTime = now
}
if limiter.tokens > 0 {
limiter.tokens--
return true
} else {
return false
}
}
func main() {
limiter := NewTokenBucketLimiter(1.5, 10)
for i := 0; i < 20; i++ {
if limiter.AllowRequest() {
fmt.Println("Allow")
} else {
fmt.Println("Reject")
}
time.Sleep(100 * time.Millisecond)
}
}
总之,Golang提供了很多实现限流的方法,每种方法都有其适用的场景。固定窗口计数器算法适用于简单场景,漏斗算法适用于平滑限流,令牌桶算法适用于各种复杂场景。根据不同的需求,选择合适的限流算法能够有效保护系统。