这是我参与「第三届青训营 -后端场」笔记创作活动的第2篇笔记
限流
在互联网上需要限流的场景有很多,比如双11购物节,秒杀系统,12306抢票等。一般会在某一时刻流量激增,如果这时不进行限流,超过了系统所能承受的负荷,服务就有可能挂掉,所以需要限流机制来保护服务的安全。
常用限流策略
- 漏桶算法
假设有一个水桶,水桶上方会以固定速率掉落水滴,不论打入服务的请求量有多大,请求速率有多快,都以恒定速率往下掉水滴。也就是说系统会以固定速率处理请求
虽然漏桶算法会以恒定速率处理请求,但是它并不能很好的处理有大量突发请求的场景。
关于漏桶的具体实现,uber团队有一个库github.com/uber-go/rat…
rl := ratelimit.New(100) // per second
prev := time.Now()
for i := 0; i < 10; i++ {
now := rl.Take() //返回漏桶下一次滴水的时间
fmt.Println(i, now.Sub(prev))
prev = now
- 令牌桶算法
令牌桶算法的原理是系统会以恒定的速率产生令牌,然后把令牌放到令牌桶中,令牌桶有一个容量,当令牌桶满了的时候,如果这时再向桶中放令牌,那么多余的令牌会被丢弃;当想要处理一个请求的时候,需要从令牌桶中取出一个令牌,如果此时令牌桶中没有令牌,那么则拒绝该请求。令牌桶能够处理激增的请求。
当取不到令牌的时候就会直接返回,或者也可以等待新的令牌。对于令牌桶的Go语言实现,大家可以参照github.com/juju/rateli…库。
在此次青训营项目中使用到了令牌桶算法限流。
在gin框架中,可以将限流组件定义成中间件。具体令牌数量应根据QPS的数值而定。
func RateLimit() func(c *gin.Context) {
bucket := ratelimit.NewBucket(time.Second, 1700)
return func(c *gin.Context) {
// 如果取不到令牌就返回响应
if bucket.TakeAvailable(1) < 1 {
c.Abort()
return
}
// 取到令牌放行
c.Next()
}
}