基于redis的分布式限频库
版权声明 本站原创文章 由 萌叔 发表
转载请注明 萌叔 | https://vearne.cc
总述
这个库的目标是为了能够简单粗暴的实现分布式限频功能, 类似于ID生成器的用法,
client每次从Redis拿回-批数据(在这里只是一个数值)进行消费,
只要没有消费完,就没有达到频率限制。
优势
- 依赖少,只依赖redis,不需要专门的服务
- 使用的redis自己的时钟,不需要相应的服务器时钟完全一致
- 线程(协程)安全
- 系统开销小,对redis的压力很小
安装
go get github.com/vearne/ratelimit
用法
1. 创建 redis.Client
依赖 "github.com/go-redis/redis"
client := redis.NewClient(&redis.Options{
Addr: "localhost:6379",
Password: "xxx", // password set
DB: 0, // use default DB
})
2. 创建限频器
limiter, _ := ratelimit.NewRedisRateLimiter(client,
"push",
1 * time.Second,
200,
10,
ratelimit.TokenBucketAlg,
)
表示允许每秒操作200次
limiter, _ := ratelimit.NewRedisRateLimiter(client,
"push",
1 * time.Minute,
200,
10,
ratelimit.TokenBucketAlg,
)
表示允许每分钟操作200次
函数原型如下:
func NewRedisRateLimiter(client *redis.Client, key string,
duration time.Duration, throughput int, batchSize int, alg int) (*RedisRateLimiter, error)
参数 | 说明 |
---|---|
key | redis中key |
duration | 表明在duration时间间隔内允许操作throughput次 |
throughput | 表明在duration时间间隔内允许操作throughput次 |
batchSize | 每次从redis拿回的可用操作的数量 |
alg | 可选的算法, 目前的合法值为 ratelimit.TokenBucketAlg : "令牌桶算法" ratelimit.CounterAlg : "计数器算法" |
注意
频率 = throughput / duration
另外为了保证性能足够高,duration的最小精度是秒
完整例子
package main
import (
"fmt"
"github.com/go-redis/redis"
"math/rand"
"github.com/vearne/ratelimit"
"sync"
"time"
)
func consume(r *ratelimit.RedisRateLimiter, group *sync.WaitGroup) {
for {
if r.Take() {
group.Done()
} else {
time.Sleep(time.Duration(rand.Intn(10)+1) * time.Millisecond)
}
}
}
func main() {
client := redis.NewClient(&redis.Options{
Addr: "localhost:6379",
Password: "xxxxx", // password set
DB: 0, // use default DB
})
limiter, _ := ratelimit.NewRedisRateLimiter(client,
"push",
1*time.Second,
100,
10,
//ratelimit.CounterAlg,
ratelimit.TokenBucketAlg,
)
var wg sync.WaitGroup
total := 5000
wg.Add(total)
start := time.Now()
for i := 0; i < 100; i++ {
go consume(limiter, &wg)
}
wg.Wait()
cost := time.Since(start)
fmt.Println("cost", time.Since(start), "rate", float64(total)/cost.Seconds())
}
依赖
致谢
模块的开发受到了资料1的启发,在此表示感谢