GO使用chan实现简单漏桶限流器

496 阅读1分钟

GO使用chan实现简单漏桶限流器

漏斗算法思想:

将所有请求先存到一个桶里。若此刻桶容量没满,表示当前请求是可以访问资源。若满了,则拒绝服务。
同时桶会以固定速率取出桶里的请求来处理

根据算法思想:

我们可以使用go的带有缓存的chan来实现简单的限流器:

先讲述一下大概的思路:

使用gin,配合中间件,在中间件内进行限流处理

上代码:

package main  
  
import (  
   "fmt"  
   "github.com/gin-gonic/gin"
   "io/ioutil"
   "log"
   "net/http"
)  
  
var q chan struct{}  
  
func init() {  
   // 缓冲chan的容量是3 (桶的容量为3) 
  q = make(chan struct{}, 3)  
}  
  
func main() {  
   go func() {  
      r := gin.Default()  
      r.Use(Middleware())  
      r.GET("/q", func(c *gin.Context) {  
         c.JSON(http.StatusOK, gin.H{"mag": "get"})  
         return  
      })  
      _ = r.Run(":8050")  
   }()  
  
   // 模仿请求  
  for {  
      res, err := http.Get("http://localhost:8050/q")  
      if err != nil {  
         fmt.Println(err)  
         return  
      }  
      robots, err := ioutil.ReadAll(res.Body)  
      res.Body.Close()  
      if err != nil {  
         log.Fatal(err)  
      }  
      fmt.Printf("%s \n", robots)  
   }  
}  
  
func Middleware() gin.HandlerFunc {  
   return func(c *gin.Context) {  
      fmt.Println(len(q))  
      if len(q) == 3 {   // 如果等于3意味着达到最大值,直接返回重试  
	  c.JSON(http.StatusOK, gin.H{"msg": "稍后重试!"})  
          return  
      }  
      // 如果通过上面的if,此处会向chan写入一个空结构体,占用一个位置,可以根据业务设置相关的结构体  
      q <- struct{}{}  
      c.Next()   // 使用gin的.Next函数,让当前请求调用下一handler继续执行下去  
      <- q // 当handler全部执行完之后,释放一个位置
  }  
}