- 資訊首頁(yè) > 開(kāi)發(fā)技術(shù) > 編程語(yǔ)言 >
- go-zero中怎么扛住流量沖擊
go-zero中怎么扛住流量沖擊,相信很多沒(méi)有經(jīng)驗的人對此束手無(wú)策,為此本文總結了問(wèn)題出現的原因和解決方法,通過(guò)這篇文章希望你能解決這個(gè)問(wèn)題。
const ( burst = 100 rate = 100 seconds = 5 ) store := .NewRedis("localhost:6379", "node", "") fmt.Println(store.Ping()) // New tokenLimiter limiter := limit.NewTokenLimiter(rate, burst, store, "rate-test") timer := time.NewTimer(time.Second * seconds) quit := make(chan struct{}) defer timer.Stop() go func() { <-timer.C close(quit) }() var allowed, denied int32 var wait sync.WaitGroup for i := 0; i < runtime.NumCPU(); i++ { wait.Add(1) go func() { for { select { case <-quit: wait.Done() return default: if limiter.Allow() { atomic.AddInt32(&allowed, 1) } else { atomic.AddInt32(&denied, 1) } } } }() } wait.Wait() fmt.Printf("allowed: %d, denied: %d, qps: %d\n", allowed, denied, (allowed+denied)/seconds)
從整體上令牌桶生產(chǎn)token邏輯如下:
用戶(hù)配置的平均發(fā)送速率為r,則每隔1/r秒一個(gè)令牌被加入到桶中;
假設桶中最多可以存放b個(gè)令牌。如果令牌到達時(shí)令牌桶已經(jīng)滿(mǎn)了,那么這個(gè)令牌會(huì )被丟棄;
當流量以速率v進(jìn)入,從桶中以速率v取令牌,拿到令牌的流量通過(guò),拿不到令牌流量不通過(guò),執行熔斷邏輯;
go-zero
在兩類(lèi)限流器下都采取 lua script
的方式,依賴(lài)redis可以做到分布式限流,lua script
同時(shí)可以做到對 token 生產(chǎn)讀取操作的原子性。
下面來(lái)看看 lua script
控制的幾個(gè)關(guān)鍵屬性:
-- 返回是否可以活獲得預期的token local rate = tonumber(ARGV[1]) local capacity = tonumber(ARGV[2]) local now = tonumber(ARGV[3]) local requested = tonumber(ARGV[4]) -- fill_time:需要填滿(mǎn) token_bucket 需要多久 local fill_time = capacity/rate -- 將填充時(shí)間向下取整 local ttl = math.floor(fill_time*2) -- 獲取目前 token_bucket 中剩余 token 數 -- 如果是第一次進(jìn)入,則設置 token_bucket 數量為 令牌桶最大值 local last_tokens = tonumber(redis.call("get", KEYS[1])) if last_tokens == nil then last_tokens = capacity end -- 上一次更新 token_bucket 的時(shí)間 local last_refreshed = tonumber(redis.call("get", KEYS[2])) if last_refreshed == nil then last_refreshed = 0 end local delta = math.max(0, now-last_refreshed) -- 通過(guò)當前時(shí)間與上一次更新時(shí)間的跨度,以及生產(chǎn)token的速率,計算出新的token數 -- 如果超過(guò) max_burst,多余生產(chǎn)的token會(huì )被丟棄 local filled_tokens = math.min(capacity, last_tokens+(delta*rate)) local allowed = filled_tokens >= requested local new_tokens = filled_tokens if allowed then new_tokens = filled_tokens - requested end -- 更新新的token數,以及更新時(shí)間 redis.call("setex", KEYS[1], ttl, new_tokens) redis.call("setex", KEYS[2], ttl, now) return allowed
上述可以看出 lua script
:只涉及對 token 操作,保證 token 生產(chǎn)合理和讀取合理。
從上述流程中看出:
有多重保障機制,保證限流一定會(huì )完成。
如果redis limiter
失效,至少在進(jìn)程內rate limiter
兜底。
重試 redis limiter
機制保證盡可能地正常運行。
go-zero
中的 tokenlimit
限流方案適用于瞬時(shí)流量沖擊,現實(shí)請求場(chǎng)景并不以恒定的速率。令牌桶相當預請求,當真實(shí)的請求到達不至于瞬間被打垮。當流量沖擊到一定程度,則才會(huì )按照預定速率進(jìn)行消費。
但是生產(chǎn)token
上,不能按照當時(shí)的流量情況作出動(dòng)態(tài)調整,不夠靈活,還可以進(jìn)行進(jìn)一步優(yōu)化。此外可以參考Token bucket WIKI中提到分層令牌桶,根據不同的流量帶寬,分至不同排隊中。
免責聲明:本站發(fā)布的內容(圖片、視頻和文字)以原創(chuàng )、來(lái)自互聯(lián)網(wǎng)轉載和分享為主,文章觀(guān)點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權請聯(lián)系站長(cháng)郵箱:ts@56dr.com進(jìn)行舉報,并提供相關(guān)證據,一經(jīng)查實(shí),將立刻刪除涉嫌侵權內容。
Copyright ? 2009-2021 56dr.com. All Rights Reserved. 特網(wǎng)科技 版權所有 珠海市特網(wǎng)科技有限公司 粵ICP備16109289號
域名注冊服務(wù)機構:阿里云計算有限公司(萬(wàn)網(wǎng)) 域名服務(wù)機構:煙臺帝思普網(wǎng)絡(luò )科技有限公司(DNSPod) CDN服務(wù):阿里云計算有限公司 中國互聯(lián)網(wǎng)舉報中心 增值電信業(yè)務(wù)經(jīng)營(yíng)許可證B2