若是這是第二次看到個人文章,歡迎點擊文末連接訂閱個人我的公衆號(跨界架構師)喲~每週五11:45 按時送達。固然了,也會時不時加個餐~前端
本文長度爲4069字,建議閱讀11分鐘。java
也許你對降級已經有了一些認識,認真看完,我想這篇文章可能會給你帶來一些新的收穫~nginx
前面兩篇咱們已經聊過了「熔斷」(如何在處處是「雷」的系統中「明哲保身」?這是第一招)和「限流」(想通關「限流」?只要這一篇),此次咱們聊的就是「高可用三劍客」中剩下的「降級」。程序員
不知道這裏有多少小夥伴接觸過阿里的開放平臺。在每次大促的時候,阿里都會發布這樣的一個公告。數據庫
這些調整就是「降級」工做,目的是爲了騰出更多資源給核心程序使用,以最大化保證核心業務的可用性,所以就必然須要對非核心業務執行一些降級處理。後端
降級的目的用一句話歸納就是:將有限的資源效益最大化。瀏覽器
什麼樣纔是效益最大化呢?就像下面這個例子:緩存
z哥有3個東西要買,一個3000的A、一個700的B、一個1200的C,對z哥的重要程度A>B>C。但此時,z哥手裏只有3000塊錢,你說z哥該怎麼選才能把錢花的最多?必然是選A咯。bash
根據28原則,咱們知道一個系統80%的效益是由最核心的20%的功能產出的。剩下的20%效益須要投入80%的資源才能達到。微信
這就意味着,假如系統平時須要花費100%資源作100%的事情,若是如今訪問量增多3倍的話一定扛不住(須要300%的資源)。那麼,在不增長資源的狀況下,我但願系統不能宕機,依舊能正常工做,必然須要讓出那解決剩下20%問題的80%資源。如此一來,理論上這100%的資源就能夠支撐原先5倍的訪問量。反作用是功能的完整性上受損80%。
固然,在實際的場景中不會降級掉80%的功能這麼誇張,畢竟還得爲用戶的體驗考慮。
舉個電商場景典型的例子,在大促的時候,最重要的是什麼?轉化咯~賺錢咯~ 那麼這個時候若是說「評論」功能佔用了不少資源,你會怎麼處理?其實咱們能夠選擇臨時關閉提交評論入口、關閉翻頁功能等等,讓下單的過程有更多的資源來處理。
常見的降級方案表現形式無非如下三種類型。
爲了減小對「冷數據」的獲取,禁用列表的翻頁功能。
爲了放緩流量進入的速率,增長驗證碼機制。
爲了減小「大查詢」浪費過多的資源,提升篩選條件要求(禁用模糊查詢、部分條件必選等)。
用通用的靜態化數據代替「千人千面」的動態數據。
甚至更簡單粗暴的,直接掛一個頁面顯示「XX功能在XX時間內暫時關閉」。
此類方案雖然或多或少下降了用戶的體驗,可是在某些時期,有些功能並非「剛需」。以此換取對系統的保護是筆劃算的買賣。
還有一些功能是「防護性」的,若是願意冒險「裸奔」一段時間也會帶來可觀的資源節約。
好比經過臨時關閉「風控」、取消部分「條件是否知足」的判斷(如,將積分商品添加到購物車時判斷積分夠不夠)等操做,減小這類「驗證」動做以釋放更多的資源。
又或者將本來info、warning級別的日誌採集關閉或者直接不採集,僅採集error以及fault級別的日誌。
一個事件發生後立馬看到效果是一個很符合「思惟慣性」的東西。可是根據以前的一篇文章(分佈式系統關注點——數據一致性(上篇))咱們知道,時效性這個東西一旦涉及到網絡傳輸是不存在真正的「實時」的。可是爲了儘量快的將處理後的結果反映到相關的地方,你會作不少努力。好比庫存的及時同步。
若是在特殊時期,可以臨時下降對時效性的要求(3秒內生效變成30秒生效),也是一個有不錯收益的方案。
好比原先在商品頁會顯示當前還剩多少個庫存,如今能夠調整成固定顯示「有貨」。
以及將一些本來就是異步進行的操做,處理效率放緩,甚至暫緩一段時間。如,送積分、送券等等。
講了這麼多,降級具體實施起來要怎麼作呢?
主要分爲兩個環節:定級定序和降級實現。
就像前面的例子中提到的同樣,首先咱們得先肯定每一個功能的「重要程度」,它決定了在什麼狀況下能夠拋棄它以保證剩下的功能可用。
相似於給日誌定義級別同樣,好比咱們能夠定義1~5五個級別,1的級別最高,要拼死保護。5的級別最低最早能夠被降級掉。
一旦當系統壓力過大的時候,先把級別5的功能降級掉。若是還不夠再降級別四、級別3,以此類推。
但實際上光這樣定級還不夠,好比被定義爲4級的有100個功能,須要降級的時候是一塊兒降級嗎?很明顯粒度太粗了。
若是「定級」比如是橫着切蛋糕的話,「定序」就是再來豎着切。
咱們也能夠來定義一些數字,好比序號1~9,序號9最早被降級。
而後,你能夠以每一個程序所支撐的上游程序/功能數量做爲一個參考標準。好比,一樣是級別5的程序,一個支撐了上游5個功能,一個支撐了10個功能,很顯然前者的序號應該更大,更先被降級。
固然,根據所支撐的功能數量只是一個「業務無關性」的通用辦法。若是想精益求精,還須要對每一個功能作「做用」上的分析,畢竟不一樣功能之間的相對重要性仍是有所差別的。(這裏能夠擴展瞭解一下Analytic Hierarchy Process,層次分析法,簡稱AHP)
對了,定級定序的時候有一點是須要格外注意的:某個程序所依賴的下游程序的級別不能低於該程序的級別。
爲何呢?由於一旦所依賴的程序被降級了,天然會致使其所支撐的全部上游程序不可用。因此,其上游程序的等級再高也是沒有意義的。
至此,完成了「排兵佈陣」,接下來就是「實施運做」了。
首先要制定觸發機制。這同熔斷、限流同樣,何時該觸發「降級」這個動做也須要依賴提早制定的一些策略。這部份內容和前面兩篇(熔斷、限流)相似,無非是接口的超時率、錯誤率,或者系統的資源耗用率等,這裏就不重複展開了。
當程序發現知足了降級條件進入「降級模式」後,程序該如何處理請求呢?
全局變量 int _runLevel = 3; //運行系統級別,默認值5
所有變量 int _runIndex = 7; //運行系統序號,默認值9
//如下是一個level=四、index=8的功能示例。
if(myLevel > _runLevel and myIndex > _runIndex){
// 進入降級模式。
}else{
// do something...
}複製代碼
題外話:經過Aop+註解(特性)的方式來作上面的if判斷是一個爽的事情。
雖然處理請求的方式有不少,但特別強調的是,要實現的降級策略要儘量的簡單。由於「邊際效應」的存在,爲了應對突發情況把事情反而搞複雜了就得不償失了。
那麼在實現部分,若是是前端。咱們比較常見的是:
在返回的http報文中經過Cache-Control的設置,讓後續的請求直接走瀏覽器緩存。
頁面中本來須要異步加載的數據,直接不加載。
禁用部分操做按鈕,甚至直接告知「臨時關閉」。
動態頁面的url經過反響代理切換到靜態頁面返回。
這裏面除了禁用按鈕外,大部分事情均可以在接入層,如nginx中處理掉,這樣能夠避免對業務項目的代碼侵入。
若是是後端程序的話,針對「讀」類型的操做,能夠將「// 進入降級模式」部分代碼寫成下面的樣子:
若是是無返回值方法。默認return或者throw一個異常。
若是是有返回值方法。默認返回本地mock的數據或者throw一個異常。
後端部分若是有使用一些中間件的話,直接在中間件(rpc、mq代理等)中處理掉是極好的(通常會內置一個fallback接口待實現),如此也能夠避免對業務代碼的侵入。
最後咱們來聊聊後端程序的「寫」問題。
緩存是大型系統中的常客,隨着系統規模越大,爲了在性能和成本上尋求更優,不可避免的會增長複雜度引入多級緩存。如此就會變成:本地緩存 --> 分佈式緩存 --> DB/源服務,這樣的一個層層遞進的關係。
平時的代碼多是這樣的:
if(write數據庫(data) == true){
if(write分佈式緩存(data) == true){
write本地緩存(data);
return success;
}
else{
rollback數據庫(data);
return fail;
}
}
else{
return fail;
}複製代碼
在高負載時期,咱們能夠下降對一致性的要求。將耗時的「數據落盤」操做降級爲「異步」進行。
if(write分佈式緩存(data) == true){
write本地緩存(data);
pushMessage(data); //發出的消息能夠經過集中式的MQ、也能夠直接寫本地磁盤。
return success;
}
else{
return fail;
}複製代碼
甚至,若是能夠的話能作的更完全,同步到分佈式緩存也異步進行。
write本地緩存(data);
pushMessage(data); //發出的消息能夠經過集中式的MQ、也能夠直接寫本地磁盤。
return success;複製代碼
數據庫是系統的最後一座堡壘,非非很是極端的狀況下,咱們能夠把一些「寫數據」操做在「數據庫訪問框架」中給禁用了,讓給全部資源都給到「讀數據」。使得系統從表象上來看至少仍是「活着站在那」的,雖然不少功能操做一下就是返回失敗(這不也是實在沒辦法了嘛,面子得要啊,死撐~)。
至此咱們聊了作降級的思路以及最多見的一些實現方式,可是真正要把降級最好是一個任重而道遠的過程。
從方案的角度來講,若是降級的過程需對每一個功能/程序逐一進行,那麼理論上10個功能點就能夠產生P(10,10)= 3628800種方案。
再從現實的角度來講,流量又是不可預測的。某些功能可能此次須要做爲level2來看待,下次其實做爲level3就夠了。
因此這是一個須要長期不斷打磨和調優的過程。
最後,但願近期的「高可用三劍客」能夠做爲你瞭解「高可用」的起點,能夠先收藏防身(固然再分享一下也是極好的:)),歡迎後續一塊兒交流探討~
Question:
你曾經是否有遇到過什麼場景,當時是經過立刻改代碼來「降級」呢?歡迎來吐槽~
相關文章:
▶ 關於做者:張帆(Zachary,我的微信號:Zachary-ZF)。堅持用心打磨每一篇高質量原創。本文首發於公衆號:「 跨界架構師」(ID:Zachary_ZF)。 <-- 點擊後閱讀熱門文章
若是你是初級程序員,想提高但不知道如何下手。又或者作程序員多年,陷入了一些瓶頸想拓寬一下視野。歡迎關注個人公衆號「 跨界架構師」,回覆「 技術」,送你一份我長期收集和整理的思惟導圖。
若是你是運營,面對不斷變化的市場一籌莫展。又或者想了解主流的運營策略,以豐富本身的「倉庫」。歡迎關注個人公衆號「 跨界架構師」,回覆「 運營」,送你一份我長期收集和整理的思惟導圖。
按期發表原創內容:架構設計丨分佈式系統丨產品丨運營丨一些深度思考。