Guava工具類 微服務(wù)如何限制接口調(diào)用次數(shù)?
微服務(wù)如何限制接口調(diào)用次數(shù)?這種限制接口調(diào)用次數(shù)的通常被稱為限流,那么為什么要限制流量呢?一般有兩個原因:1.首先是防止服務(wù)提供者被大量的請求淹沒。我們在開發(fā)一個項目的時候,理想的情況是可以正常響應(yīng)很
微服務(wù)如何限制接口調(diào)用次數(shù)?
這種限制接口調(diào)用次數(shù)的通常被稱為限流,那么為什么要限制流量呢?一般有兩個原因:
1.首先是防止服務(wù)提供者被大量的請求淹沒。
我們在開發(fā)一個項目的時候,理想的情況是可以正常響應(yīng)很多請求,但是在現(xiàn)在的互聯(lián)網(wǎng)環(huán)境下,我們很難評估用戶的增長,訪問的數(shù)量,甚至有時候會遇到惡意攻擊;那么,與其項目被流量碾壓,不如限制流量,只滿足部分接入的正常響應(yīng)。
簡單來說:滿足所有請求,滿足部分請求,項目被碾壓,所有請求都無法響應(yīng)。
充電
目前很多平臺開發(fā)的接口并不都是免費的。比如普通會員一天只能調(diào)用接口1000次,高級會員一天可以調(diào)用接口10萬次,或者按調(diào)用量收費。
那么如何限制服務(wù)接口調(diào)用的次數(shù)呢?
使用電流限制算法
通常我們可以通過限流算法來限制接口調(diào)用的次數(shù),比如計數(shù)器法、滑動窗口法、漏桶、令牌桶算法,這里我們以令牌桶算法為例。
令牌桶算法,我們可以把它想象成一個桶,里面有n個令牌,系統(tǒng)會勻速把令牌放進桶里。在每次處理之前,我們必須首先獲得令牌。如果我們能 如果得不到,我們將拒絕服務(wù)。這里我們使用Google生產(chǎn)的Guava工具庫,它提供了一個開箱即用的令牌桶速率限制器。
如圖,我們寫了一個簡單的接口,省略了業(yè)務(wù)邏輯,只返回一個字符串;我們設(shè)置(2),這意味著每秒提交的任務(wù)不超過2個。
讓 使用接口工具模擬并發(fā)調(diào)用:
他逼他堅強,我卻立場堅定。因為我們使用限流算法,并且每秒只處理2個請求,所以我們可以從日志中看到每秒只有2個日志的效果。
分布式架構(gòu)下的電流限制
由于使用了開源組件,限流的實現(xiàn)看起來很簡單,但是這里也有一個很大的問題,就是實例是一個應(yīng)用包,但是在實際項目中,我們通常是通過集群部署的將我們的應(yīng)用部署在多臺機器上,那么這個時候如何限流呢?
每臺服務(wù)器上的應(yīng)用程序控制自己的響應(yīng)數(shù)量?比如一天只能調(diào)100次,如果調(diào)配10臺,總數(shù)就變成1000次;
反推?因為總量一天只能調(diào)100次,調(diào)配10個單位,也就是每個單位一天只能調(diào)10次?這是一個非常糟糕的方法。更不用說流量可以平均分配到每臺機器。如果一機掛機,今天只能支持90個嗎?
通常的解決方案是在公共場所(如熱地)將令牌放入令牌桶,而不是在本地。在S中,每次請求到來時,都會計算是否超過限制的總量。如果沒有超過,則正常處理,如果超過,則返回錯誤消息。
具體來說,Redis中的key-100作為令牌桶,100表示一分鐘可以調(diào)用100次,每次處理前將值減1,返回值大于0,表示可以處理;每分鐘將數(shù)值設(shè)回100;或者計數(shù)累加,從0開始,不斷累加,最后超過單位時間的總量限制;
但是,這個方法應(yīng)該有一個定時任務(wù)來設(shè)置令牌的數(shù)量。此外,這種方法可以 t應(yīng)對突發(fā)流量,比如前59秒沒有請求,第60秒來了100個請求,第61秒來了100個請求,實際上兩秒處理了200個請求。
另一種方案是使用Redis中的有序隊列排序集來存儲近100次的調(diào)用時間。每次有新請求時,將隊列中第一個元素的時間與當(dāng)前時間進行比較。如果相差超過1分鐘,說明沒有超過流量限制,然后進行處理,把第一個元素推出隊列,把新的請求時間推入隊列。
我會繼續(xù)分享我對Java開發(fā)、架構(gòu)設(shè)計、程序員職業(yè)發(fā)展等方面的看法,希望得到大家的關(guān)注。