golang配额管理与速率限制工具插件库equalizer的使用

Golang配额管理与速率限制工具插件库equalizer的使用

equalizer是一个Go语言实现的简单易用的速率限制器集合,可以用于限制对数据库、API或文件等任何资源的请求速率。

Equalizer

Equalizer是一个根据先前请求结果调整请求速率的限流器。如果之前的尝试失败,Equalizer会降低请求速率以避免系统过载;如果之前的尝试成功,Equalizer会提高请求速率以充分利用可用容量。

使用示例

// 创建一个随机偏移管理器
offset := equalizer.NewRandomOffset(96)
// 创建一个Equalizer,位图大小为96,16个保留正数位,使用随机偏移管理器
eq := equalizer.NewEqualizer(96, 16, offset)
// 非阻塞式配额请求
haveQuota := eq.TryAcquire()
// 请求成功后更新状态
eq.Success(1)

性能基准

BenchmarkEqualizer_ShortTryAcquireStep-16       31538967                38.33 ns/op            0 B/op          0 allocs/op
BenchmarkEqualizer_ShortTryAcquireRandom-16     37563639                31.66 ns/op            0 B/op          0 allocs/op
BenchmarkEqualizer_ShortNotify-16               29519719                40.43 ns/op            0 B/op          0 allocs/op
BenchmarkEqualizer_LongTryAcquireStep-16        32084402                38.36 ns/op            0 B/op          0 allocs/op
BenchmarkEqualizer_LongTryAcquireRandom-16      39996501                30.37 ns/op            0 B/op          0 allocs/op
BenchmarkEqualizer_LongNotify-16                29648655                40.46 ns/op            0 B/op          0 allocs/op

Slider

Slider跟踪最近时间窗口内已处理的请求数量。如果请求数超过限制,速率限制器将阻止新请求,直到窗口向前移动。实现了equalizer.Limiter接口。

使用示例

// 创建一个Slider,窗口大小为1秒,滑动间隔100毫秒,容量32
slider := equalizer.NewSlider(time.Second, 100*time.Millisecond, 32)
// 非阻塞式配额请求
haveQuota := slider.TryAcquire()
// 阻塞式调用
slider.Acquire(context.Background())

性能基准

BenchmarkSlider_TryAcquire-16                   293645348                4.033 ns/op           0 B/op          0 allocs/op
BenchmarkRateLimiter_Allow-16                     9362382              127.4 ns/op             0 B/op          0 allocs/op

Token Bucket

TokenBucket维护固定数量的令牌。每个令牌代表一个可以处理的请求。当发出请求时,速率限制器检查是否有可用令牌。如果有,则处理请求并移除一个令牌;如果没有,则阻塞请求直到有令牌可用。实现了equalizer.Limiter接口。

使用示例

// 创建一个TokenBucket,容量32,补充间隔100毫秒
tokenBucket := equalizer.NewTokenBucket(32, 100*time.Millisecond)
// 非阻塞式配额请求
haveQuota := tokenBucket.TryAcquire()
// 阻塞式调用
tokenBucket.Acquire(context.Background())

性能基准

BenchmarkTokenBucket_TryAcquire-16              304653043                3.909 ns/op           0 B/op          0 allocs/op
BenchmarkRateLimiter_Allow-16                     9362382              127.4 ns/op             0 B/op          0 allocs/op

完整示例Demo

package main

import (
	"context"
	"fmt"
	"time"

	"github.com/reugn/equalizer"
)

func main() {
	// Equalizer示例
	offset := equalizer.NewRandomOffset(96)
	eq := equalizer.NewEqualizer(96, 16, offset)
	if eq.TryAcquire() {
		fmt.Println("Equalizer: 获取配额成功")
		eq.Success(1)
	}

	// Slider示例
	slider := equalizer.NewSlider(time.Second, 100*time.Millisecond, 32)
	if slider.TryAcquire() {
		fmt.Println("Slider: 获取配额成功")
	}
	
	// 带超时的阻塞调用
	ctx, cancel := context.WithTimeout(context.Background(), time.Second)
	defer cancel()
	if err := slider.Acquire(ctx); err == nil {
		fmt.Println("Slider: 阻塞获取配额成功")
	}

	// TokenBucket示例
	tokenBucket := equalizer.NewTokenBucket(32, 100*time.Millisecond)
	if tokenBucket.TryAcquire() {
		fmt.Println("TokenBucket: 获取配额成功")
	}
	
	// 阻塞调用
	if err := tokenBucket.Acquire(context.Background()); err == nil {
		fmt.Println("TokenBucket: 阻塞获取配额成功")
	}
}

许可证

使用MIT许可证授权。


更多关于golang配额管理与速率限制工具插件库equalizer的使用的实战教程也可以访问 https://www.itying.com/category-94-b0.html

1 回复

更多关于golang配额管理与速率限制工具插件库equalizer的使用的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


Golang配额管理与速率限制工具equalizer使用指南

equalizer是一个轻量级的Go语言配额管理与速率限制库,它提供了简单易用的API来实现各种速率限制策略。下面我将详细介绍equalizer的使用方法。

安装

go get github.com/platinummonkey/equalizer

基本使用

1. 固定窗口限流器

package main

import (
	"fmt"
	"time"
	
	"github.com/platinummonkey/equalizer/fixedwindow"
)

func main() {
	// 创建一个每秒最多允许5个请求的限流器
	limiter := fixedwindow.NewFixedWindowRateLimiter(5, time.Second)
	
	for i := 0; i < 10; i++ {
		if limiter.Limit() {
			fmt.Printf("Request %d: Allowed\n", i+1)
		} else {
			fmt.Printf("Request %d: Rate limited\n", i+1)
		}
		time.Sleep(200 * time.Millisecond)
	}
}

2. 滑动窗口限流器

package main

import (
	"fmt"
	"time"
	
	"github.com/platinummonkey/equalizer/slidingwindow"
)

func main() {
	// 创建一个滑动窗口限流器,每秒钟最多5个请求
	limiter := slidingwindow.NewSlidingWindowRateLimiter(5, time.Second, 10) // 10个桶
	
	for i := 0; i < 15; i++ {
		if limiter.Limit() {
			fmt.Printf("Request %d: Allowed\n", i+1)
		} else {
			fmt.Printf("Request %d: Rate limited\n", i+1)
		}
		time.Sleep(100 * time.Millisecond)
	}
}

3. 令牌桶限流器

package main

import (
	"fmt"
	"time"
	
	"github.com/platinummonkey/equalizer/tokenbucket"
)

func main() {
	// 创建一个令牌桶限流器,容量为10,每秒新增2个令牌
	limiter := tokenbucket.NewTokenBucketRateLimiter(10, 2)
	
	for i := 0; i < 15; i++ {
		if limiter.Limit() {
			fmt.Printf("Request %d: Allowed\n", i+1)
		} else {
			fmt.Printf("Request %d: Rate limited\n", i+1)
		}
		time.Sleep(300 * time.Millisecond)
	}
}

高级功能

1. 动态调整限流参数

package main

import (
	"fmt"
	"time"
	
	"github.com/platinummonkey/equalizer/tokenbucket"
)

func main() {
	limiter := tokenbucket.NewTokenBucketRateLimiter(10, 2)
	
	// 动态调整令牌桶容量和填充速率
	limiter.UpdateRate(20)      // 更新容量为20
	limiter.UpdateFillRate(5)   // 更新填充速率为5/秒
	
	// 使用更新后的参数
	for i := 0; i < 25; i++ {
		if limiter.Limit() {
			fmt.Printf("Request %d: Allowed\n", i+1)
		} else {
			fmt.Printf("Request %d: Rate limited\n", i+1)
		}
		time.Sleep(200 * time.Millisecond)
	}
}

2. 多维度限流

package main

import (
	"fmt"
	"time"
	
	"github.com/platinummonkey/equalizer/multilimiter"
)

func main() {
	// 创建多维度限流器
	limiter := multilimiter.NewMultiLimiter()
	
	// 添加多个限流规则
	limiter.AddLimiter("user1", fixedwindow.NewFixedWindowRateLimiter(5, time.Second))
	limiter.AddLimiter("user2", tokenbucket.NewTokenBucketRateLimiter(10, 2))
	
	// 检查不同用户的限流状态
	for i := 0; i < 10; i++ {
		user := "user1"
		if i%2 == 0 {
			user = "user2"
		}
		
		if limiter.Limit(user) {
			fmt.Printf("Request %d for %s: Allowed\n", i+1, user)
		} else {
			fmt.Printf("Request %d for %s: Rate limited\n", i+1, user)
		}
		time.Sleep(200 * time.Millisecond)
	}
}

HTTP中间件示例

package main

import (
	"fmt"
	"net/http"
	"time"
	
	"github.com/platinummonkey/equalizer/fixedwindow"
)

var limiter = fixedwindow.NewFixedWindowRateLimiter(100, time.Minute)

func rateLimitMiddleware(next http.Handler) http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		if limiter.Limit() {
			next.ServeHTTP(w, r)
		} else {
			http.Error(w, "Rate limit exceeded", http.StatusTooManyRequests)
		}
	})
}

func handler(w http.ResponseWriter, r *http.Request) {
	fmt.Fprintf(w, "Hello, World!")
}

func main() {
	mux := http.NewServeMux()
	mux.HandleFunc("/", handler)
	
	wrappedMux := rateLimitMiddleware(mux)
	
	fmt.Println("Server starting on :8080")
	http.ListenAndServe(":8080", wrappedMux)
}

性能考虑

equalizer在设计时考虑了性能因素,但仍有几点需要注意:

  1. 对于高并发场景,考虑使用sync.Pool来重用限流器对象
  2. 滑动窗口限流器的桶数量会影响内存使用和精度
  3. 令牌桶限流器在极端高并发下可能有性能瓶颈

equalizer提供了简单而强大的速率限制功能,适用于API限流、用户配额管理等多种场景。根据具体需求选择合适的限流算法,可以有效地保护系统免受过载影响。

回到顶部