您好,登錄后才能下訂單哦!
這期內(nèi)容當(dāng)中小編將會給大家?guī)碛嘘P(guān)go-zero 中怎樣扛住流量沖擊,文章內(nèi)容豐富且以專業(yè)的角度為大家分析和敘述,閱讀完這篇文章希望大家可以有所收獲。
不管是在單體服務(wù)中還是在微服務(wù)中,開發(fā)者為前端提供的API接口都是有訪問上限的,當(dāng)訪問頻率或者并發(fā)量超過其承受范圍時(shí)候,我們就必須考慮限流來保證接口的可用性或者降級可用性。即接口也需要安裝上保險(xiǎn)絲,以防止非預(yù)期的請求對系統(tǒng)壓力過大而引起的系統(tǒng)癱瘓。
go-zero
集成了開箱即用的 限流器 。其中內(nèi)置了兩種限流器,也對應(yīng)兩類使用場景:
種類 | 原理 | 場景 |
---|---|---|
periodlimit | 單位時(shí)間限制訪問次數(shù) | 需要強(qiáng)行限制數(shù)據(jù)的傳輸速率 |
tokenlimit | 令牌桶限流 | 限制數(shù)據(jù)的平均傳輸速率,同時(shí)允許某種程度的突發(fā)傳輸 |
const ( seconds = 1 total = 100 quota = 5 ) // New limiter l := NewPeriodLimit(seconds, quota, redis.NewRedis(s.Addr(), redis.NodeType), "periodlimit") // take source code, err := l.Take("first") if err != nil { logx.Error(err) return true } // switch val => process request switch code { case limit.OverQuota: logx.Errorf("OverQuota key: %v", key) return false case limit.Allowed: logx.Infof("AllowedQuota key: %v", key) return true case limit.HitQuota: logx.Errorf("HitQuota key: %v", key) // todo: maybe we need to let users know they hit the quota return false default: logx.Errorf("DefaultQuota key: %v", key) // unknown response, we just let the sms go return true }
go-zero
采取 滑動窗口 計(jì)數(shù)的方式,計(jì)算一段時(shí)間內(nèi)對同一個(gè)資源的訪問次數(shù),如果超過指定的 limit
,則拒絕訪問。當(dāng)然如果你是在一段時(shí)間內(nèi)訪問不同的資源,每一個(gè)資源訪問量都不超過 limit
,此種情況是允許大量請求進(jìn)來的。
而在一個(gè)分布式系統(tǒng)中,存在多個(gè)微服務(wù)提供服務(wù)。所以當(dāng)瞬間的流量同時(shí)訪問同一個(gè)資源,如何讓計(jì)數(shù)器在分布式系統(tǒng)中正常計(jì)數(shù)? 同時(shí)在計(jì)算資源訪問時(shí),可能會涉及多個(gè)計(jì)算,如何保證計(jì)算的原子性?
go-zero
借助 redis
的 incrby
做資源訪問計(jì)數(shù)
采用 lua script
做整個(gè)窗口計(jì)算,保證計(jì)算的原子性
下面來看看 lua script
控制的幾個(gè)關(guān)鍵屬性:
argument | mean |
---|---|
key[1] | 訪問資源的標(biāo)示 |
ARGV[1] | limit => 請求總數(shù),超過則限速??稍O(shè)置為 QPS |
ARGV[2] | window大小 => 滑動窗口,用 ttl 模擬出滑動的效果 |
-- to be compatible with aliyun redis, -- we cannot use `local key = KEYS[1]` to reuse thekey local limit = tonumber(ARGV[1]) local window = tonumber(ARGV[2]) -- incrbt key 1 => key visis++ local current = redis.call("INCRBY", KEYS[1], 1) -- 如果是第一次訪問,設(shè)置過期時(shí)間 => TTL = window size -- 因?yàn)槭侵幌拗埔欢螘r(shí)間的訪問次數(shù) if current == 1 then redis.call("expire", KEYS[1], window) return 1 elseif current < limit then return 1 elseif current == limit then return 2 else return 0 end
至于上述的 return code
,返回給調(diào)用方。由調(diào)用方來決定請求后續(xù)的操作:
return code | tag | call code | mean |
---|---|---|---|
0 | OverQuota | 3 | over limit |
1 | Allowed | 1 | in limit |
2 | HitQuota | 2 | hit limit |
下面這張圖描述了請求進(jìn)入的過程,以及請求觸發(fā) limit
時(shí)后續(xù)發(fā)生的情況:
如果在服務(wù)某個(gè)時(shí)間點(diǎn),請求大批量打進(jìn)來,periodlimit
短期時(shí)間內(nèi)達(dá)到 limit
閾值,而且設(shè)置的時(shí)間范圍還遠(yuǎn)遠(yuǎn)沒有到達(dá)。后續(xù)請求的處理就成為問題。
periodlimit
中并沒有處理,而是返回 code
。把后續(xù)請求的處理交給了開發(fā)者自己處理。
如果不做處理,那就是簡單的將請求拒絕
如果需要處理這些請求,開發(fā)者可以借助 mq
將請求緩沖,減緩請求的壓力
采用 tokenlimit
,允許暫時(shí)的流量沖擊
上述就是小編為大家分享的go-zero 中怎樣扛住流量沖擊了,如果剛好有類似的疑惑,不妨參照上述分析進(jìn)行理解。如果想知道更多相關(guān)知識,歡迎關(guān)注億速云行業(yè)資訊頻道。
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。