golang实现限流

发布时间:2024-07-05 01:30:47

实现限流的常用方法

在高并发的系统中,经常需要对接口进行限流,以避免系统崩溃或过载。Golang提供了很多实现限流的方法,本文将介绍一些常用的方法。

1. 固定窗口计数器算法

固定窗口计数器算法是一种简单直观的限流算法。它基于滑动窗口的思想,将一段时间分成固定大小的窗口,在每个窗口内设置一个计数器,记录请求的次数。当请求到来时,如果计数器的值超过了设定的阈值,则拒绝请求。

以下是一个使用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)
    }
}

2. 漏斗算法

漏斗算法是一种比较适用于平滑限流的算法。它模拟了一个漏斗,在漏斗中的水以固定的速率流出,当请求到来时,如果漏斗还有剩余容量,则允许通过。

以下是一个使用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)
    }
}

3. 令牌桶算法

令牌桶算法是一种广泛应用于限流场景的算法。它维护了一个桶,桶中存放着令牌。当请求到来时,如果桶中有令牌,则允许通过,并消耗一个令牌;如果桶中没有令牌,则拒绝请求。

以下是一个使用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提供了很多实现限流的方法,每种方法都有其适用的场景。固定窗口计数器算法适用于简单场景,漏斗算法适用于平滑限流,令牌桶算法适用于各种复杂场景。根据不同的需求,选择合适的限流算法能够有效保护系统。

相关推荐