背景
商家自主新增配件需求(Freemarker+JQuery
前後端未分離專案)中,追加配件彈窗內批量複製貼上配件會迴圈呼叫獲取聯想詞介面,如果複製貼上的配件名稱很多(20+),只有一部分請求成功(狀態碼200)返回響應體,其他請求成功(狀態碼204)但沒有返回響應體。
問題分析
對比釋出詢價頁、追加配件頁發現這三個頁面都有同樣的問題,為什麼迴圈併發呼叫介面會報204呢?跟運維、架構溝通後發現,這個問題的根源是閘道器層多了防爬、限流處理,因為當我們的系統被頻繁的請求的時候,就有可能 將系統壓垮,有了閘道器,那麼就可以在閘道器係統做限流,因為所有的請求都需要先通過閘道器係統才能路由到微服務中。
令牌桶演算法
令牌桶演算法是比較常見的限流演算法之一,大概描述如下:
1)所有的請求在處理之前都需要拿到一個可用的令牌才會被處理;
2)根據限流大小,設定按照一定的速率往桶裡新增令牌;
3)桶設定最大的放置令牌限制,當桶滿時、新新增的令牌就被丟棄或者拒絕;
4)請求達到後首先要獲取令牌桶中的令牌,拿著令牌才可以進行其他的業務邏輯,處理完業務邏輯之後,將令牌直接刪除;
5)令牌桶有最低限額,當桶中的令牌達到最低限額的時候,請求處理完之後將不會刪除令牌,以此保證足夠的限流
如下圖:
在cass-webagent
閘道器專案中,限流配置如下:
icec:
limiter:
enabled: true
pathConfig:
burstCapacity: 10 #令牌桶的容量,同一個地址允許在一秒鐘內完成的最大請求數
replenishRate: 5 #允許使用者每秒處理多少個請求
routeConfig:
burstCapacity: 50 #令牌桶的容量,同一個服務允許在一秒鐘內完成的最大請求數
replenishRate: 20 #允許使用者每秒處理多少個請求
customConfigs: #自定義令牌桶的容量
- name: "path:/agentBuy/decodePartNo"
config.burstCapacity: 500
- name: "path:/agentBuy/getFastOEMore"
config.burstCapacity: 500
- name: "path:/maindata/llq/getDitchPriceSingle"
config.burstCapacity: 100
#- name: "route:web-market"
# config.burstCapacity: 51
當使用者一秒內請求數量超過20個時,可能有一部分請求返回204(no content
)
解決方案
1、前端控制每秒的請求併發數
比如,每個一個時間段傳送一定量級的請求,利用一個偽死迴圈阻塞主執行緒,體驗效果會很不好
//第一種,使用while迴圈
function sleep(delay) {
var start = (new Date()).getTime();
while((new Date()).getTime() - start < delay) {
continue;
}
}
//或者使用for迴圈
function sleep(delay) {
for(var t = Date.now(); Date.now() - t <= d;);
}
2、在閘道器增加自定義某些介面路徑允許使用者每秒處理的請求量,會增加後端服務壓力
3、將迴圈呼叫改成批量介面,這才是最徹底的解決方案
總結
本文僅僅是這類問題做一個分析記錄,在開發中我們要避免這種迴圈呼叫介面的場景。