為什么需要限流
在微服務(wù)架構(gòu)下雾狈,若大量請求超過微服務(wù)的處理能力時(shí),可能會(huì)將服務(wù)打跨爬橡,甚至產(chǎn)生雪崩效應(yīng)治唤、影響系統(tǒng)的整體穩(wěn)定性。比如說你的用戶服務(wù)處理能力是1w/s糙申,現(xiàn)在因?yàn)楫惓A髁炕蚱渌虮鎏恚?0w的并發(fā)請求訪問你的服務(wù),那你的服務(wù)肯定扛不住啊柜裸。這種情況下缕陕,我們可以在流量超出承受閾值時(shí),直接進(jìn)行”限流”疙挺、拒絕部分請求扛邑,從而保證系統(tǒng)的整體穩(wěn)定性。
限流算法
固定時(shí)間窗口
基于固定時(shí)間窗口的限流算法是非常簡單的铐然。首先需要選定一個(gè)時(shí)間起點(diǎn)蔬崩,之后每次接口請求到來都累加計(jì)數(shù)器,如果在當(dāng)前時(shí)間窗口內(nèi)搀暑,根據(jù)限流規(guī)則(比如每秒鐘最大允許 100 次接口請求)沥阳,累加訪問次數(shù)超過限流值,則限流熔斷拒絕接口請求自点。當(dāng)進(jìn)入下一個(gè)時(shí)間窗口之后桐罕,計(jì)數(shù)器清零重新計(jì)數(shù)。
缺點(diǎn)
限流策略過于粗略,無法應(yīng)對兩個(gè)時(shí)間窗口臨界時(shí)間內(nèi)的突發(fā)流量功炮。我們舉一個(gè)例子:假設(shè)我們限流規(guī)則為每秒鐘不超過 100 次接口請求溅潜,第一個(gè) 1s 時(shí)間窗口內(nèi),100 次接口請求都集中在最后的 10ms 內(nèi)薪伏,在第二個(gè) 1s 的時(shí)間窗口內(nèi)滚澜,100 次接口請求都集中在最開始的 10ms 內(nèi),雖然兩個(gè)時(shí)間窗口內(nèi)流量都符合限流要求 (<=100 個(gè)請求)嫁怀,但在兩個(gè)時(shí)間窗口臨界的 20ms 內(nèi)會(huì)集中有 200 次接口請求博秫,如果不做限流,集中在這 20ms 內(nèi)的 200 次請求就有可能壓垮系統(tǒng)眶掌。
滑動(dòng)時(shí)間窗口算法
滑動(dòng)時(shí)間窗口算法是對固定時(shí)間窗口算法的一種改進(jìn),流量經(jīng)過滑動(dòng)時(shí)間窗口算法整形之后巴碗,可以保證任意時(shí)間窗口內(nèi)朴爬,都不會(huì)超過最大允許的限流值橡淆,從流量曲線上來看會(huì)更加平滑,可以部分解決上面提到的臨界突發(fā)流量問題逸爵。對比固定時(shí)間窗口限流算法,滑動(dòng)時(shí)間窗口限流算法的時(shí)間窗口是持續(xù)滑動(dòng)的师倔,并且除了需要一個(gè)計(jì)數(shù)器來記錄時(shí)間窗口內(nèi)接口請求次數(shù)之外构韵,還需要記錄在時(shí)間窗口內(nèi)每個(gè)接口請求到達(dá)的時(shí)間點(diǎn)疲恢,對內(nèi)存的占用會(huì)比較多。
缺點(diǎn)
即便滑動(dòng)時(shí)間窗口限流算法可以保證任意時(shí)間窗口內(nèi)接口請求次數(shù)都不會(huì)超過最大限流值瓷胧,但是仍然不能防止在細(xì)時(shí)間粒度上面訪問過于集中的問題,比如上面舉的例子搓萧,第一個(gè) 1s 的時(shí)間窗口內(nèi) 100 次請求都集中在最后 10ms 中。也就是說瘸洛,基于時(shí)間窗口的限流算法,不管是固定時(shí)間窗口還是滑動(dòng)時(shí)間窗口货矮,只能在選定的時(shí)間粒度上限流羊精,對選定時(shí)間粒度內(nèi)的更加細(xì)粒度的訪問頻率不做限制。
漏桶和令牌桶算法
漏桶算法(Leaky Bucket):主要目的是控制數(shù)據(jù)注入到網(wǎng)絡(luò)的速率,平滑網(wǎng)絡(luò)上的突發(fā)流量喧锦。漏桶算法提供了一種機(jī)制读规,通過它,突發(fā)流量可以被整形以便為網(wǎng)絡(luò)提供一個(gè)穩(wěn)定的流量燃少。漏桶算法的示意圖如下:
請求先進(jìn)入到漏桶里束亏,漏桶以一定的速度出水,當(dāng)水請求過大會(huì)直接溢出阵具,可以看出漏桶算法能強(qiáng)行限制數(shù)據(jù)的傳輸速率碍遍。
令牌桶算法(Token Bucket):是網(wǎng)絡(luò)流量整形(Traffic Shaping)和速率限制(Rate Limiting)中最常使用的一種算法。典型情況下阳液,令牌桶算法用來控制發(fā)送到網(wǎng)絡(luò)上的數(shù)據(jù)的數(shù)目怕敬,并允許突發(fā)數(shù)據(jù)的發(fā)送。令牌桶算法示意圖如下所示:
大小固定的令牌桶可自行以恒定的速率源源不斷地產(chǎn)生令牌帘皿。如果令牌不被消耗东跪,或者被消耗的速度小于產(chǎn)生的速度,令牌就會(huì)不斷地增多鹰溜,直到把桶填滿虽填。后面再產(chǎn)生的令牌就會(huì)從桶中溢出。最后桶中可以保存的最大令牌數(shù)永遠(yuǎn)不會(huì)超過桶的大小曹动。
漏桶和令牌桶算法的區(qū)別
令牌桶算法斋日,主要放在服務(wù)端,用來保護(hù)服務(wù)端(自己)墓陈,主要用來對調(diào)用者頻率進(jìn)行限流恶守,為的是不讓自己被壓垮。所以如果自己本身有處理能力的時(shí)候跛蛋,如果流量突發(fā)(實(shí)際消費(fèi)能力強(qiáng)于配置的流量限制=桶大邪镜摹),那么實(shí)際處理速率可以超過配置的限制(桶大猩藜丁)押框。
而漏桶算法,主要放在調(diào)用方理逊,這是用來保護(hù)他人橡伞,也就是保護(hù)他所調(diào)用的系統(tǒng)。主要場景是晋被,當(dāng)調(diào)用的第三方系統(tǒng)本身沒有保護(hù)機(jī)制兑徘,或者有流量限制的時(shí)候,我們的調(diào)用速度不能超過他的限制羡洛,由于我們不能更改第三方系統(tǒng)挂脑,所以只有在主調(diào)方控制。這個(gè)時(shí)候,即使流量突發(fā)崭闲,也必須舍棄肋联。因?yàn)橄M(fèi)能力是第三方?jīng)Q定的刁俭。
自適應(yīng)限流
一般的限流常常需要指定一個(gè)固定值(qps)作為限流開關(guān)的閾值牍戚,這個(gè)值一是靠經(jīng)驗(yàn)判斷,二是靠通過大量的測試數(shù)據(jù)得出宪哩。但這個(gè)閾值第晰,在流量激增但荤、系統(tǒng)自動(dòng)伸縮或者某某commit了一段有毒代碼后就有可能變得不那么合適了腹躁。并且一般業(yè)務(wù)方也不太能夠正確評估自己的容量,去設(shè)置一個(gè)合適的限流閾值纺非。那么我們就可以考慮用自適應(yīng)限流來解決這個(gè)問題烧颖。
對于自適應(yīng)限流來說, 一般都是結(jié)合系統(tǒng)的 Load窄陡、CPU 使用率以及應(yīng)用的入口 QPS、平均響應(yīng)時(shí)間和并發(fā)量等幾個(gè)維度的監(jiān)控指標(biāo)涂圆,通過自適應(yīng)的流控策略, 讓系統(tǒng)的入口流量和系統(tǒng)的負(fù)載達(dá)到一個(gè)平衡币叹,讓系統(tǒng)盡可能跑在最大吞吐量的同時(shí)保證系統(tǒng)整體的穩(wěn)定颈抚。
分布式限流
上面使用的限流算法,都是基本單節(jié)點(diǎn)限流的。但線上業(yè)務(wù)出于各種原因考慮锚赤,多是分布式系統(tǒng)宴树,單節(jié)點(diǎn)的限流僅能保護(hù)自身節(jié)點(diǎn)晶疼,但無法保護(hù)應(yīng)用依賴的各種服務(wù),并且在進(jìn)行節(jié)點(diǎn)擴(kuò)容翠霍、縮容時(shí)也無法準(zhǔn)確控制整個(gè)服務(wù)的請求限制寒匙。比如說我希望某個(gè)接口的QPS的1000次/秒,服務(wù)部署在5臺(tái)機(jī)器上考蕾,雖然我們可以通過配置每臺(tái)節(jié)點(diǎn)200次/秒來限流会宪。但如果節(jié)點(diǎn)收縮或者擴(kuò)容,那么久不能滿足需求了塞帐。而且不同服務(wù)的物理配置不一定相同葵姥,可能有些節(jié)點(diǎn)處理得比較快榔幸,那么配置均值來限流,就不是一個(gè)好方法了牡辽。
常見的分布式限流策略
網(wǎng)關(guān)層限流:將限流規(guī)則應(yīng)用在所有流量的入口處态辛,比如nigix+lua
中間件限流:將限流信息存儲(chǔ)在分布式環(huán)境中某個(gè)中間件里(比如Redis緩存)挺尿,每個(gè)組件都可以從這里獲取到當(dāng)前時(shí)刻的流量統(tǒng)計(jì)炊邦,從而決定是拒絕服務(wù)還是放行流量馁害。
參考資料
https://www.infoq.cn/article/microservice-interface-rate-limit
https://lailin.xyz/post/go-training-week6-4-auto-limiter.html