漏桶算法
go get -u go.uber.org/ratelimit
"go.uber.org/ratelimit"
我们可以简单理解为:有一个漏桶,然后不断往这个漏桶里面加水,无论加多少水,这个漏桶流出的速率是固定的,不会因为流入水的多少而改变,从而实现了水流控制,也就是限流操作。
下面是个简单代码示例:
最重要的一个参数就是 ratelimit1.New(n),这个 n 就是两滴水流间的时间间隔。单位是纳秒
我们用下一滴水滴下落时间 - 当前 时间,如果大于0,说明还没有到达下一次水滴 滴落时间,此时还需要进行限流操作。
func rateLimit1() func(ctx *gin.Context) {
// 生成一个限流器, 参数:两滴水滴的时间间隔
rl := ratelimit1.New(3)
return func(c *gin.Context) {
if rl.Take().Sub(time.Now()) > 0 { // 检查是否需要进行限流。下一滴水滴时间 - 当前时间
//time.Sleep(rl.Take().Sub(time.Now())) // 需要等这么长时间 下一滴水才会滴下来
c.String(200, "rate limit...")
c.Abort()
return
}
c.Next()
}
}
r.GET("/ping", rateLimit1(), pingHandler)
令牌桶算法
go get -u github.com/juju/ratelimit
"github.com/juju/ratelimit"
令牌桶算法,根据令牌桶中令牌的个数来控制请求的执行。
具体的说,令牌桶算法会不断的生成令牌并放入到令牌桶中,每个请求在执行之前,都需要从令牌桶中获取一个令牌,如果此时获取不到令牌则需要等待,直到令牌桶中有令牌为止。
下面就是一个简单代码示例:第一个参数是 令牌桶中多久填充一个新的令牌,第二个参数是 定义令牌桶的最大容量
然后创建一个令牌桶,从令牌桶中获取令牌,如果每次最少能获取一个,如果此时令牌桶里有令牌,请求可以执行,如果没有令牌,则中止当前的请求。
注意: 这里使用到了闭包,保证整个项目中只有一个令牌桶对象,并且所有的请求都共享同一个令牌桶。
func rateLimit2(fillInterval time.Duration, cap int64) func(ctx *gin.Context) {
rl := ratelimit2.NewBucket(fillInterval, cap) // 创建了一个令牌桶
return func(c *gin.Context) {
//rl.Take() // 要取几个就取几个,比如要取 两个,则数量如果小于2 直接阻塞
// rl.TakeAvailable() // 可以少取,比如 要取两个,如果只有一个,那就先取一个,不会阻塞
if rl.TakeAvailable(1) == 1 { // 检查是否 至少有一个令牌可以用 括号中是要检查的令牌数量
c.Next()
return
}
c.String(200, "被限流了,请等待!!!")
c.Abort()
}
}
r.GET("/hei", rateLimit2(2*time.Second, 1), heiHandler)