go-kit 微服務 限流 (uber/ratelimit 和 golang/rate 實現)
golang/rate 簡介(golang.org/x/time/rate)
- golang 標準庫中就自帶的限流演算法
- 該限流器是基於 Token Bucket(令牌桶) 實現的
//第一個引數是 r Limit。代表每秒可以向 Token 桶中產生多少 token
//第二個引數是 b int。b 代表 Token 桶的容量大小
golangLimit := rate.NewLimiter(10, 1)
//golangLimit 其令牌桶大小為 1, 以每秒 10 個 Token 的速率向桶中放置 Token。
- Wait/WaitN
- Wait 實際上就是 WaitN(ctx,1)
- 當使用 Wait 方法時,如果令牌桶內 Token(大於 or 等於 N)直接返回,如果當時令牌桶內 Token 不足 (小於 N),那麼 Wait 方法將會阻塞,直到能從令牌桶內獲得 Token
- Allow/AllowN
- Allow 實際上就是 AllowN(time.Now(),1)。
- 當使用使用 AllowN 方法時,截止到 time.Now() 這一時刻 (time 可以自己傳入) 令牌桶中數目必須(大於 or 等於 N),滿足則返回正確,同時從令牌桶中消費 N 個 Token
- 應用場景請求速度太快就直接丟掉一些請求
- Reserve/ReserveN
- Reserve 相當於 ReserveN(time.Now(), 1)
- 當使用使用 ReserveN 方法時,不管能不能從令牌桶內獲取到 Token 都會返回一個 Reservation 物件
- Reservation 物件的 Ok() 方法返回了令牌桶是否可以在最大等待時間內提供請求的令牌數量,如果 OK 為 false,則 Delay() 返回 InfDuration
- Reservation 物件的 Delay() 方法返回了需要等待的時間,如果時間為 0 則不需要等待
- 如果不想等待就呼叫 Reservation 物件的 Cancel()
uber/ratelimit 簡介(go.uber.org/ratelimit)
- uber 開源的限流演算法,
- 該元件基於 Leaky Bucket(漏桶) 實現的
//一秒請求一次
uberLimit := ratelimit.New(1)
//使用方法
uberLimit.Take()
Endpoint 層修改
- 新增基於 golang.org/x/time/rate 的限流中介軟體
func NewGolangRateAllowMiddleware(limit *rate.Limiter) endpoint.Middleware {
return func(next endpoint.Endpoint) endpoint.Endpoint {
return func(ctx context.Context, request interface{}) (response interface{}, err error) {
if !limit.Allow() {
return "", errors.New("limit req Allow")
}
return next(ctx, request)
}
}
}
- 新增基於 go.uber.org/ratelimit 的限流中介軟體
func NewUberRateMiddleware(limit ratelimit.Limiter) endpoint.Middleware {
return func(next endpoint.Endpoint) endpoint.Endpoint {
return func(ctx context.Context, request interface{}) (response interface{}, err error) {
limit.Take()
return next(ctx, request)
}
}
}
- 對於需要限流的方法新增限流中介軟體
func NewEndPointServer(svc v4_service.Service, log *zap.Logger, limit *rate.Limiter, limiter ratelimit.Limiter) EndPointServer {
var addEndPoint endpoint.Endpoint
{
addEndPoint = MakeAddEndPoint(svc)
addEndPoint = LoggingMiddleware(log)(addEndPoint)
addEndPoint = AuthMiddleware(log)(addEndPoint)
addEndPoint = NewUberRateMiddleware(limiter)(addEndPoint)
}
var loginEndPoint endpoint.Endpoint
{
loginEndPoint = MakeLoginEndPoint(svc)
loginEndPoint = LoggingMiddleware(log)(loginEndPoint)
loginEndPoint = NewGolangRateAllowMiddleware(limit)(loginEndPoint)
}
return EndPointServer{AddEndPoint: addEndPoint, LoginEndPoint: loginEndPoint}
}
激動人心的時刻來了,修改 main 方法
utils.NewLoggerServer()
golangLimit := rate.NewLimiter(10, 1) //每秒產生10個令牌,令牌桶的可以裝1個令牌
uberLimit := ratelimit.New(1) //一秒請求一次
server := v4_service.NewService(utils.GetLogger())
endpoints := v4_endpoint.NewEndPointServer(server, utils.GetLogger(), golangLimit, uberLimit)
httpHandler := v4_transport.NewHttpHandler(endpoints, utils.GetLogger())
utils.GetLogger().Info("server run 0.0.0.0:8888")
_ = http.ListenAndServe("0.0.0.0:8888", httpHandler))
日誌(一秒請求 100 次介面)
日誌比較多這裡我減少了一些日誌以便於觀看
go.uber.org/ratelimit 的限流中介軟體
2020-01-03 09:46:30 DEBUG v4_transport/transport.go:70 5fd6eae3-32ea-5a24-9507-ed3c865f2e50 {" 開始解析請求資料": {"a":1,"b":1}}
2020-01-03 09:46:31 DEBUG v4_transport/transport.go:70 ca39186b-c4e1-5976-bb02-f5e484aeca48 {" 開始解析請求資料": {"a":1,"b":1}}
2020-01-03 09:46:32 DEBUG v4_transport/transport.go:70 691bfdf1-6701-553f-ae78-d443eff6fb6b {" 開始解析請求資料": {"a":1,"b":1}}
......
可以看到請求是按照我們控制的一秒一秒請求的
- golang.org/x/time/rate 的限流中介軟體
2020-01-03 09:42:17 DEBUG v4_transport/transport.go:75 cc74b82d-4fa9-558c-acd3-ad2ea292dfdd {"請求結束封裝返回值":"token"}}
2020-01-03 09:42:17 WARN v4_transport/transport.go:20 c1a00c56-edad-55b0-b546-076a0d070086 {"error": "limit req Allow"}
2020-01-03 09:42:17 DEBUG v4_transport/transport.go:75 2c8ab986-c300-5df1-99fc-0d88c8db8c40 {"請求結束封裝返回值":"token"}}
2020-01-03 09:42:17 WARN v4_transport/transport.go:20 8e5dc5d4-e048-56c7-9a42-33863843cd67 {"error": "limit req Allow"}
......
結語
- 在請求數量過多且我們的服務處理不完時,新增限流能保證我們服務的健康狀態
- 在文章中我只展示了下限流在 go-kit 裡面的簡單使用
- 歡迎新增 QQ 一起討論
完整程式碼地址
聯絡 QQ: 3355168235
更多原創文章乾貨分享,請關注公眾號
- 加微信實戰群請加微信(註明:實戰群):gocnio
相關文章
- go-kit微服務:限流Go微服務
- Golang 標準庫 限流器 time/rate 設計與實現Golang
- go-kit 微服務 服務監控 (prometheus 實現)Go微服務Prometheus
- go-kit 微服務實踐Go微服務
- Golang 限流器的使用和實現Golang
- go-kit 微服務 服務鏈路追蹤 (jaeger 實現)(2)Go微服務
- go-kit 微服務 服務鏈路追蹤 (jaeger 實現)(1)Go微服務
- go-kit微服務:服務註冊與發現Go微服務
- go-kit微服務:HTTP RESTGo微服務HTTPREST
- go-kit微服務:服務熔斷Go微服務
- .NET服務治理之限流中介軟體-FireflySoft.RateLimitMIT
- go-kit微服務:API監控Go微服務API
- go-kit微服務:日誌功能Go微服務
- go-kit微服務系列目錄Go微服務
- go-kit微服務:JWT身份認證Go微服務JWT
- go-kit微服務:服務鏈路追蹤Go微服務
- Asp-Net-Core開發筆記:使用RateLimit中介軟體實現介面限流筆記MIT
- [開源] Golang 實現的分散式 WebSocket 微服務Golang分散式Web微服務
- Golang 微服務優化實戰Golang微服務優化
- go-kit 微服務 系列文章歸檔Go微服務
- 雲原生時代 PHP/Golang 專案如何實現微服務PHPGolang微服務
- Kubernetes 微服務最佳實踐微服務
- Uber微服務實戰經驗分享微服務
- 使用Golang和MongoDB構建微服務GolangMongoDB微服務
- 微服務容錯限流框架Hystrix微服務框架
- go-kit 微服務 日誌分析管理 (ELK + Filebeat)Go微服務
- go.uber.org/ratelimit 原始碼分析GoMIT原始碼
- 微服務熔斷限流Hystrix之流聚合微服務
- 微服務容錯限流Hystrix入門微服務
- 微服務熔斷限流Hystrix之Dashboard微服務
- Golang之微服務為什麼發現不了Golang微服務
- Welcome to YARP - 4.限流 (Rate Limiting)MIT
- 基於Golang的微服務——Micro實踐(一)Golang微服務
- 基於Golang的微服務——Micro實踐(二)Golang微服務
- golang 微服務-基礎元件Golang微服務元件
- 利用Spring Boot實現微服務的API閘道器統一限流與熔斷Spring Boot微服務API
- [分散式限流] 滑動視窗演算法的 Golang 實現分散式演算法Golang
- go-kit微服務:一個簡單的API閘道器Go微服務API