架構與思維:熔斷限流的一些使用場景

1 前言

在《微服務系列》中,我們講過很多限流,熔斷相關的知識。
老生長談的一個話題,服務的能力終歸是有限的,無論是內存、CPU、線程數都是,如果遇到突如其來的峯量請求,我們怎麼友好的使用限流來進行落地,避免整個服務集羣的雪崩。

峯量請求主要有兩種場景:

1.1 突發高峯造成的服務雪崩

如果你的服務突然遇到持續性的、高頻率的、不符合預期的突發流量。你需要檢查一下服務是否有被錯誤調用、惡意攻擊,或者下游程序邏輯問題。
這種超出預期的調用經常會造成你的服務響應延遲,請求堆積,甚至服務雪崩。而雪崩會隨着調用鏈向上傳遞,導致整個服務鏈的崩潰,對我們的系統造成很大的隱患。

1.2 超出預期值的流量洪峯

如果你的商城或者平臺搞活動(類似雙 11、618),但你又無法有效評估出這個峯值的具象值和持續時間,那麼你的服務依然有被打垮的風險。
除非你能做到服務集羣彈性伸縮(動態擴縮容)的能力,這個我在後面的雲原生系列中會詳細說。

如上圖,正常量值爲 1500 QPS,預估模型的量值是 2600 QPS,後面發現,來了幾波活動,量值增加到 10000,遠超過我們服務器的負載。服務一過載,系統就開始出現各種問題,延遲、故障、請求堆積,甚至雪崩。

2 解決方案

2.1 雲原生和彈性伸縮

如果你的服務基架構與足夠強大,你的服務上雲足夠的徹底,那麼彈性伸縮是最好的辦法。類似淘寶、京東、百度 APP,都是類似的做法。
kubernetes 會根據流量的變化,CPU、內存的曲線過程實時計算需要的服務實例數,然後進行動態擴容,低峯期再還回去。這個要求你的服務上雲足夠徹底,並且有足夠的資源來達成資源擴容的目標。
★關於這塊內容筆者後續會有專門的系列來講解,以及如何在大廠實現落地的過程,這邊不展開。

2.2 兜底的限流、熔斷

最基本的保障就是能夠在服務做一層保護,避免因爲過載而造成服務雪崩,導致整個系統不可用.
對超過預期或者承載能力的流量進行限流是比較好的一種辦法。所以你在雙 11、618、搶購、競拍 等的選擇的時候會經常看到這樣的詞彙:

2.1 應用層面解決方案

2.1.1 常見的限流算法

計數算法是指在一定的時間間隔裏,記錄請求次數,當時間間隔到期之後,就把計數清零,重新計算。

相對於上一個 計數限流,多了個時間窗口的概念,計數器每過一個時間窗口就重置,重新開始計算。

滑動窗口限流解決固定窗口臨界值的問題,可以保證在任意時間窗口內都不會超過閾值。

類似沙漏思維,大家都用過,沙子是勻速流出的。對於漏桶來說,由於它的出水口的速度是恆定的,也就是消化處理請求的速度是恆定的,所以它可以保證服務以恆定的速率來處理請求,

令牌桶和漏桶的原理類似,只不過漏桶是定速流出,令牌桶是定速流入(即往桶裏塞入令牌),每個請求進來,分配一個令牌,只有拿到了令牌才能進入服務器處理,拿不到令牌的就被拒絕了。
因爲令牌桶的大小也是有限制的,所以一旦令牌桶滿,後續生成的令牌就會被丟棄,拿不到令牌的服務請求就被拒絕了,達到限流的目的。執行原理如下:

2.1.2 相關實現的框架

2.1.3 達到限流條件的時候的做法

fallback:返回固定的對象或者執行固定的方法

// 返回固定的對象
{
"timestamp": 1649756501928,
"status": 429,
"message": "Too Many Requests",
}

// 執行固定的處理方法
function  fallBack(Context ctx) {
   // Todo 默認的處理邏輯
}

2.1.4 Web/Mobile/PC/3d

接收到固定的消息結構或者固定的處理結果之後,以友好的方式提示給用戶。

2.2 存儲層面解決方案

Redis 熱點數據同時併發請求處理,1000W + 請求同時投向後端,如果緩存未建立,直接投向數據庫,可能會造成擊穿,怎麼破?一般有如下解決方法,優劣各異:

3 總結

無論是應用層級還是存儲層級,無非是跟前端約定一個規則,返回默認參數或者默認回到方法,讓前端以用戶友好體驗的方式進行降級,保證服務端不至於崩潰。

本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源https://mp.weixin.qq.com/s/_JYeFvk42afS_EDLLt5N2Q