Go語(yǔ)言框架快速集成限流中間件詳解
前言
在我們的日常開(kāi)發(fā)中, 常用的中間件有很多, 今天來(lái)講一下怎么集成限流中間件, 它可以很好地用限制并發(fā)訪(fǎng)問(wèn)數(shù)來(lái)保護(hù)系統(tǒng)服務(wù), 避免系統(tǒng)服務(wù)崩潰, 資源占用過(guò)大甚至服務(wù)器崩潰進(jìn)而影響到其他應(yīng)用!
分布式版
簡(jiǎn)介
通常我們的服務(wù)會(huì)同時(shí)存在多個(gè)進(jìn)程, 也就是負(fù)載來(lái)保證服務(wù)的性能和穩(wěn)定性, 那么就需要走一個(gè)統(tǒng)一的限流, 這個(gè)時(shí)候就需要借助我們的老朋友-redis, 來(lái)進(jìn)行分布式限流;
算法
漏桶算法
即一個(gè)水桶, 進(jìn)水(接受請(qǐng)求)的速率不限, 出水(處理請(qǐng)求)的速率是一定的, 如果出水的速率小于進(jìn)水的速率, 就會(huì)造成水桶溢出(也就是拒絕請(qǐng)求); 主要是從出口限制, 以固定的速率控制訪(fǎng)問(wèn)速度, 缺點(diǎn)是難以應(yīng)對(duì)突發(fā)請(qǐng)求;
實(shí)現(xiàn)
下面是一個(gè)簡(jiǎn)單的實(shí)現(xiàn), 對(duì) /v1/hello接口進(jìn)行每分鐘2次的速率限制
// RateLimitConf 速率配置, 允許多長(zhǎng)時(shí)間通過(guò)多少次.
type RateLimitConf struct {
Limit int64
Timer time.Duration
}
// exampleLimiterMap 接口請(qǐng)求速率配置, 建議放入redis/數(shù)據(jù)庫(kù)同步本地緩存.
var exampleLimiterMap = map[string]RateLimitConf{
"/v1/hello": {Limit: 2, Timer: time.Minute},
}
// LimiterMiddle 分布式限流中間件.
func LimiterMiddle(ctx iris.Context) {
var (
uri = ctx.Request().RequestURI
client = redis.NewClusterClient()
key = uri
)
conf, ok := exampleLimiterMap[uri]
if ok {
limiter := redis_rate.NewLimiter(client)
if _, _, b := limiter.Allow(key, conf.Limit, conf.Timer); !b {
r, _ := httpcode.NewRequest(ctx, nil)
r.Code(httpcode.TooManyReq, fmt.Errorf("req rate limit"), nil)
return
}
}
ctx.Next()
}
注意
- 接口速率配置如果需要進(jìn)行實(shí)時(shí)配置, 則建議將配置寫(xiě)入數(shù)據(jù)庫(kù), 然后刷新到本地緩存/存到redis;
- 如果需要對(duì)設(shè)備/ip/用戶(hù)進(jìn)行接口限制訪(fǎng)問(wèn), 則將
key加上唯一標(biāo)志即可;
單機(jī)版
簡(jiǎn)介
這個(gè)就只適用于單個(gè)服務(wù)進(jìn)程的限流, 比如個(gè)人搭的一些小網(wǎng)站之類(lèi)的;
算法
令牌桶算法
即也是一個(gè)桶, 按照設(shè)定的速率往桶里放令牌, 10s二十次即1s放兩個(gè)令牌(允許處理兩次請(qǐng)求), 然后請(qǐng)求來(lái)之后必須從桶里取出來(lái)令牌才可以進(jìn)行處理, 沒(méi)有令牌則選擇拒絕或等待; 主要是從入口限制, 允許一定量的突發(fā)請(qǐng)求(即桶內(nèi)所有的令牌);
依賴(lài)庫(kù)
實(shí)現(xiàn)
下面是一個(gè)簡(jiǎn)單的實(shí)現(xiàn), 對(duì) /v1/hello接口進(jìn)行每分鐘2次的速率限制
// exampleStandAloneLimiterMap 單機(jī)接口請(qǐng)求速率配置.
var exampleStandAloneLimiterMap = map[string]*rate.Limiter{
"/v1/hello": rate.NewLimiter(rate.Every(time.Minute), 2),
}
// StandAloneLimiterMiddle 單機(jī)限流中間件.
func StandAloneLimiterMiddle(ctx iris.Context) {
var (
uri = ctx.Request().RequestURI
)
limiter, ok := exampleStandAloneLimiterMap[uri]
if ok {
if b := limiter.Allow(); !b {
r, _ := httpcode.NewRequest(ctx, nil)
r.Code(httpcode.TooManyReq, fmt.Errorf("req rate limit"), nil)
return
}
}
ctx.Next()
}
結(jié)語(yǔ)
上面的代碼均摘自我開(kāi)發(fā)的一個(gè)開(kāi)源項(xiàng)目中, 主要是一個(gè)Go的標(biāo)準(zhǔn)項(xiàng)目布局, 封裝了一些常用的組件, 有興趣的朋友可以了解一下, 新手極易上手;
以上就是Go語(yǔ)言框架快速集成限流中間件詳解的詳細(xì)內(nèi)容,更多關(guān)于Go框架集成限流中間件的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
golang?gorm開(kāi)發(fā)架構(gòu)及寫(xiě)插件示例
這篇文章主要為大家介紹了golang?gorm開(kāi)發(fā)架構(gòu)及寫(xiě)插件的詳細(xì)示例,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步早日升職加薪2022-04-04
go語(yǔ)言for循環(huán)中嵌套defer的執(zhí)行順序
在Go語(yǔ)言中,defer語(yǔ)句用于延遲函數(shù)調(diào)用的執(zhí)行,本文主要介紹了go語(yǔ)言for循環(huán)中嵌套defer的執(zhí)行順序,具有一定的參考價(jià)值,感興趣的可以了解一下2025-03-03
從零封裝Gin框架實(shí)現(xiàn)日志初始化及切割歸檔功能
這篇文章主要為大家介紹了從零封裝Gin框架實(shí)現(xiàn)日志初始化及切割歸檔功能示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2024-01-01
Go內(nèi)存節(jié)省技巧簡(jiǎn)單實(shí)現(xiàn)方法
這篇文章主要為大家介紹了Go內(nèi)存節(jié)省技巧簡(jiǎn)單實(shí)現(xiàn)方法詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-01-01
Go語(yǔ)言學(xué)習(xí)之new函數(shù)的用法詳解
這篇文章主要為大家詳細(xì)介紹了Go語(yǔ)言中new()函數(shù)的相關(guān)知識(shí)以及具體用法,文中的示例代碼講解詳細(xì),具有一定的學(xué)習(xí)價(jià)值,感興趣的小伙伴可以了解一下2023-05-05
Golang實(shí)現(xiàn)Dijkstra算法過(guò)程詳解
Dijkstra 算法是一種用于計(jì)算無(wú)向圖的最短路徑的算法,它是基于貪心策略的,每次選擇當(dāng)前距離起始節(jié)點(diǎn)最近的未訪(fǎng)問(wèn)節(jié)點(diǎn)進(jìn)行訪(fǎng)問(wèn),并更新其相鄰節(jié)點(diǎn)的距離值,以得到最短路徑,這篇文章主要介紹了Golang實(shí)現(xiàn)Dijkstra算法,需要的朋友可以參考下2023-05-05
Go?channel實(shí)現(xiàn)批量讀取數(shù)據(jù)
Go中的?channel?其實(shí)并沒(méi)有提供批量讀取數(shù)據(jù)的方法,需要我們自己實(shí)現(xiàn)一個(gè),使用本文就來(lái)為大家大家介紹一下如何通過(guò)Go?channel實(shí)現(xiàn)批量讀取數(shù)據(jù)吧2023-12-12
gorm golang 并發(fā)連接數(shù)據(jù)庫(kù)報(bào)錯(cuò)的解決方法
今天小編就為大家分享一篇gorm golang 并發(fā)連接數(shù)據(jù)庫(kù)報(bào)錯(cuò)的解決方法,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2019-07-07

