(三)go-kit服務接口限流

前言

限流這層按說是應該在網關那做的,這裏爲了學習go kit暫時放在這裏
在middleware/rate.go使用gokit的endpointMiddleWare定義一個限流中間件,在main函數裏面將要限流的接口用這個函數裝飾一下,這個接口就能實現限流相關功能,本項目地址: github地址

1.限流原理

常見的限流方法有令牌桶和漏桶

  • 令牌桶
    令牌桶算法的原理是系統會以一個恆定的速度往桶裏放入令牌,而如果請求需要被處理,則需要先從桶裏獲取一個令牌,當桶裏沒有令牌可取時,則拒絕服務。
  • 漏桶
    漏桶算法思路很簡單,水(請求)先進入到漏桶裏,漏桶以一定的速度出水(接口有響應速率),當水流入速度過大會直接溢出(訪問頻率超過接口響應速率),然後就拒絕請求,可以看出漏桶算法能強行限制數據的傳輸速率。
  • 對比
    漏桶的漏出速率是固定的參數,所以即使網絡中不存在資源衝突(沒有發生擁塞),漏桶算法也不能使流突發(burst)到端口速率,因此,漏桶算法對於存在突發特性的流量來說缺乏效率。令牌桶算法用來控制發送到網絡上的數據的數目,並允許突發數據的發送,對於不穩定情況下的流量有一定的兼容性。本文使用更爲常見的令牌桶算法進行限流。

2. 創建限流器

在middleware/rate.go使用gokit的endpointMiddleWare定義一個限流中間件:

func NewRateLimit(interval int, burst int) endpoint.Middleware {
	limiter := rate.NewLimiter(rate.Every(time.Second*time.Duration(interval)), burst)
	return func(next endpoint.Endpoint) endpoint.Endpoint {
		return func(ctx context.Context, request interface{}) (response interface{}, err error) {
			if !limiter.Allow() {
				//這裏使用了上節的自定義錯誤
				return nil, util.NewMyError(429, "too many request,please waiting...")
			}
			return next(ctx, request)
		}
	}
}

3.修改main函數

getUserNameEndpoint := userservice.MakeGetUserNameEndpoint(svc)
//每秒鐘getUserName接口只能接受一個請求,但是可以容忍瞬間提高的5個請求,超過限制的請求會報429
getUserNameEndpoint = middleware.NewRateLimit(1, 5)(getUserNameEndpoint)

調試

  • 啓動服務,訪問localhost:8000/user/1,連續點擊url的刷新按鈕,開始會正常返回,過一會之後會返回我們在中間件裏面自定義的錯誤"too many request,please waiting…",http status code也會變成429
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章