限流策略 | 青训营笔记

123 阅读2分钟

这是我参与「第三届青训营 -后端场」笔记创作活动的第2篇笔记

限流

在互联网上需要限流的场景有很多,比如双11购物节,秒杀系统,12306抢票等。一般会在某一时刻流量激增,如果这时不进行限流,超过了系统所能承受的负荷,服务就有可能挂掉,所以需要限流机制来保护服务的安全。

常用限流策略
  • 漏桶算法
    假设有一个水桶,水桶上方会以固定速率掉落水滴,不论打入服务的请求量有多大,请求速率有多快,都以恒定速率往下掉水滴。也就是说系统会以固定速率处理请求

image.png 虽然漏桶算法会以恒定速率处理请求,但是它并不能很好的处理有大量突发请求的场景。 关于漏桶的具体实现,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
  • 令牌桶算法
    令牌桶算法的原理是系统会以恒定的速率产生令牌,然后把令牌放到令牌桶中,令牌桶有一个容量,当令牌桶满了的时候,如果这时再向桶中放令牌,那么多余的令牌会被丢弃;当想要处理一个请求的时候,需要从令牌桶中取出一个令牌,如果此时令牌桶中没有令牌,那么则拒绝该请求。令牌桶能够处理激增的请求。

image.png 当取不到令牌的时候就会直接返回,或者也可以等待新的令牌。对于令牌桶的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()
   }
}