Go利用Redis實作簡單的「固定窗口限流器(Fixed window rate limiter)」。
main.go
package main
import (
"context"
"fmt"
"time"
"github.com/go-redis/redis/v9"
)
func main() {
ctx := context.Background()
rc := NewRedisClient()
userId := "user123" // request's user id
reqCount := 10 // intense request count of the user
for i := 0; i < reqCount; i++ { // send intense requests
currentMinute := time.Now().Minute() // request time minute
if isAllowed(ctx, rc, userId, currentMinute) {
fmt.Println("pass")
} else {
fmt.Println("reject")
}
}
}
func isAllowed(ctx context.Context, rc *redis.Client, userId string, currentMiniute int) bool {
key := fmt.Sprintf("%s:%d", userId, currentMiniute) // e.g. key=user123:45
n, _ := rc.Get(ctx, key).Int()
limit := 5 // limit request count within the time window
if n >= limit {
return false
}
pipe := rc.TxPipeline() // redis MULTI/EXEC
pipe.Incr(ctx, key)
pipe.Expire(ctx, key, time.Minute) // 1minute fixed time window
_, err := pipe.Exec(ctx)
return err == nil
}
func NewRedisClient() *redis.Client {
return redis.NewClient(&redis.Options{
Addr: "localhost:6379",
Password: "12345",
DB: 0, // use default DB
})
}
測試
執行印出以下。
pass
pass
pass
pass
pass
reject
reject
reject
reject
reject
沒有留言:
張貼留言