前言

限流器是后台服务中十分重要的组件,在实际的业务场景中使用居多,其设计在网关和一些后台服务中会经常遇到。限流器的作用是用来限制其请求的速率,保护后台响应服务,以免服务过载导致服务不可用现象出现。
**
在 Golang 库中官方给我们提供了限流器的实现 golang.org/x/time/rate,它是基于令牌桶算法(Token Bucket)设计实现的。

代码实现

编写中间件

  1. // Create a rate limiter with a maximum number of operations to perform per second.
  2. func RateLimitMiddleware() gin.HandlerFunc {
  3. rateCfg := config.GetConfig().Rate
  4. r := rate.Every(time.Duration(rateCfg.Limit) * time.Second)
  5. limit := rate.NewLimiter(r, rateCfg.Burst)
  6. return func(c *gin.Context) {
  7. if !limit.Allow() {
  8. fmt.Println("The current flow is too big, please try again later")
  9. c.JSON(http.StatusOK, gin.H{
  10. "status": status.RequestRateLimit,
  11. "message": status.GetStatusMessage(status.RequestRateLimit),
  12. })
  13. c.Abort()
  14. return
  15. }
  16. }
  17. }

测试接口

  1. // Test controller
  2. middleRateLimit := md.RateLimitMiddleware()
  3. testHandler := testHandler.New()
  4. test := router.Group("/V1/internal/test", middleRateLimit)
  5. {
  6. test.GET("/rate-limit", testHandler.RateLimitTest) // Testing rate limit for request
  7. }

接口返回

  1. // Test an interface that rate limit for request
  2. func (h *handler) RateLimitTest(c *gin.Context) {
  3. c.JSON(http.StatusOK, gin.H{
  4. "status": 200,
  5. "message": "Success",
  6. })
  7. }

测试用例

Postman

http://{{baseUrl}}/V1/internal/test/rate-limit

Screen Shot 2021-03-28 at 12.27.37 AM.png

Jmeter

image.png
Screen Shot 2021-03-28 at 12.42.29 AM.png

拓展

  1. uber 开源库中基于漏斗算法实现了一个限流器。漏斗算法可以限制流量的请求速度,并起到削峰的作用。 [https://github.com/uber-go/ratelimit](https://github.com/uber-go/ratelimit)
  2. 滴滴开源实现了一个对http请求的限流器中间件。可以基于以下模式限流。
    • 基于IP,路径,方法,header,授权用户等限流
    • 通过自定义方法限流
    • 还支持基于 http header 设置限流数据
    • 实现方式是基于 github/go/time 实现的,不同类别的数据都存储在一个带超时时间的数据池中。
    • 代码地址 [https://github.com/didip/tollbooth](https://github.com/didip/tollbooth)
  3. golang 网络包中还有基于信号量实现的限流器。 [https://github.com/golang/net/blob/master/netutil/listen.go](https://github.com/golang/net/blob/master/netutil/listen.go) 也值得我们去学习下。