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