讓你的系統「堅挺不倒」的最後乙個大招 降級

2021-09-17 07:37:15 字數 4371 閱讀 5200

也許你對降級已經有了一些認識,認真看完,我想這篇文章可能會給你帶來一些新的收穫~

前面兩篇我們已經聊過了「熔斷」(如何在到處是「雷」的系統中「明哲保身」?這是第一招)和「限流」(想通關「限流」?只要這一篇),這次我們聊的就是「高可用三劍客」中剩下的「降級」。

不知道這裡有多少小夥伴接觸過阿里的開放平台。在每次大促的時候,阿里都會發布這樣的乙個公告。

▲2023年雙12的公告內容

這些調整就是「降級」工作,目的是為了騰出更多資源給核心程式使用,以最大化保證核心業務的可用性,因此就必然需要對非核心業務執行一些降級處理。

降級的目的用一句話概括就是:將有限的資源效益最大化。

什麼樣才是效益最大化呢?就像下面這個例子:

z哥有3個東西要買,乙個3000的a、乙個700的b、乙個1200的c,對z哥的重要程度a\u0026gt;b\u0026gt;c。但此時,z哥手裡只有3000塊錢,你說z哥該怎麼選才能把錢花的最多?必然是選a咯。

根據28原則,我們知道乙個系統80%的效益是由最核心的20%的功能產出的。剩下的20%效益需要投入80%的資源才能達到。

這就意味著,假如系統平時需要花費100%資源做100%的事情,如果現在訪問量增多3倍的話必定扛不住(需要300%的資源)。那麼,在不增加資源的情況下,我希望系統不能宕機,依舊能正常工作,必然需要讓出那解決剩下20%問題的80%資源。如此一來,理論上這100%的資源就可以支撐原先5倍的訪問量。***是功能的完整性上受損80%。

當然,在實際的場景中不會降級掉80%的功能這麼誇張,畢竟還得為使用者的體驗考慮。

常見的降級方案表現形式無非以下三種型別。

1.犧牲使用者體驗

為了減少對「冷資料」的獲取,禁用列表的翻頁功能。

為了放緩流量進入的速率,增加驗證碼機制。

為了減少「大查詢」浪費過多的資源,提高篩選條件要求(禁用模糊查詢、部分條件必選等)。

用通用的靜態化資料代替「千人千面」的動態資料。

甚至更簡單粗暴的,直接掛乙個頁面顯示「xx功能在xx時間內暫時關閉」。

此類方案雖然或多或少降低了使用者的體驗,但是在某些時期,有些功能並不是「剛需」。以此換取對系統的保護是筆劃算的買賣。

2.犧牲功能完整性

還有一些功能是「防禦性」的,如果願意冒險「裸奔」一段時間也會帶來可觀的資源節約。

比如通過臨時關閉「風控」、取消部分「條件是否滿足」的判斷(如,將積分商品新增到購物車時判斷積分夠不夠)等操作,減少這類「驗證」動作以釋放更多的資源。

又或者將原本info、warning級別的日誌採集關閉或者直接不採集,僅採集error以及fault級別的日誌。

3.犧牲時效性

乙個事件發生後立馬看到效果是乙個很符合「思維慣性」的東西。但是根據之前的一篇文章(分布式系統關注點——資料一致性)我們知道,時效性這個東西一旦涉及到網路傳輸是不存在真正的「實時」的。但是為了盡可能快的將處理後的結果反映到相關的地方,你會做很多努力。比如庫存的及時同步。

如果在特殊時期,能夠臨時降低對時效性的要求(3秒內生效變成30秒生效),也是乙個有不錯收益的方案。

比如原先在商品頁會顯示當前還剩多少個庫存,現在可以調整成固定顯示「有貨」。

以及將一些原本就是非同步進行的操作,處理效率放緩,甚至暫緩一段時間。如,送積分、送券等等。

講了這麼多,降級具體實施起來要怎麼做呢?

主要分為兩個環節:定級定序和降級實現。

定級定序

就像前面的例子中提到的一樣,首先我們得先確定每個功能的「重要程度」,它決定了在什麼情況下可以拋棄它以保證剩下的功能可用。

類似於給日誌定義級別一樣,比如我們可以定義1~5五個級別,1的級別最高,要拼死保護。5的級別最低最先可以被降級掉。

一旦當系統壓力過大的時候,先把級別5的功能降級掉。如果還不夠再降級別4、級別3,以此類推。

但實際上光這樣定級還不夠,比如被定義為4級的有100個功能,需要降級的時候是一起降級嗎?很明顯粒度太粗了。

如果「定級」好比是橫著切蛋糕的話,「定序」就是再來豎著切。

我們也可以來定義一些數字,比如序號1~9,序號9最先被降級。

然後,你可以以每個程式所支撐的上游程式/功能數量作為乙個參考標準。比如,同樣是級別5的程式,乙個支撐了上游5個功能,乙個支撐了10個功能,很顯然前者的序號應該更大,更先被降級。

當然,根據所支撐的功能數量只是乙個「業務無關性」的通用辦法。如果想精益求精,還需要對每個功能做「作用」上的分析,畢竟不同功能之間的相對重要性還是有所差異的。(這裡可以擴充套件了解一下analytic hierarchy process,層次分析法,簡稱ahp)

對了,定級定序的時候有一點是需要格外注意的:某個程式所依賴的下游程式的級別不能低於該程式的級別。

為什麼呢?因為一旦所依賴的程式被降級了,自然會導致其所支撐的所有上游程式不可用。所以,其上游程式的等級再高也是沒有意義的。

至此,完成了「排兵布陣」,接下來就是「實施運作」了。

降級實現

首先要制定觸發機制。這同熔斷、限流一樣,什麼時候該觸發「降級」這個動作也需要依賴提前制定的一些策略。這部分內容和前面兩篇(熔斷、限流)類似,無非是介面的超時率、錯誤率,或者系統的資源耗用率等,這裡就不重複展開了。

當程式發現滿足了降級條件進入「降級模式」後,程式該如何處理請求呢?

全域性變數 int _runlevel = 3;  //執行系統級別,預設值5全部變數 int _runindex = 7;  //執行系統序號,預設值9//以下是乙個level=4、index=8的功能示例。if(mylevel \u0026gt; _runlevel and myindex \u0026gt; _runindex)else
題外話:通過aop+註解(特性)的方式來做上面的if判斷是乙個爽的事情。

雖然處理請求的方式有很多,但特別強調的是,要實現的降級策略要盡可能的簡單。因為「邊際效應」的存在,為了應對突發狀況把事情反而搞複雜了就得不償失了。

那麼在實現部分,如果是前端。我們比較常見的是:

這裡面除了禁用按鈕外,大部分事情都可以在接入層,如nginx中處理掉,這樣可以避免對業務專案的**侵入。

如果是後端程式的話,針對「讀」型別的操作,可以將「// 進入降級模式」部分**寫成下面的樣子:

後端部分如果有使用一些中介軟體的話,直接在中介軟體(rpc、mq**等)中處理掉是極好的(一般會內建乙個fallback介面待實現),如此也可以避免對業務**的侵入。

最後我們來聊聊後端程式的「寫」問題。

快取是大型系統中的常客,隨著系統規模越大,為了在效能和成本上尋求更優,不可避免的會增加複雜度引入多級快取。如此就會變成:本地快取 --\u0026gt; 分布式快取 --\u0026gt; db/源服務,這樣的乙個層層遞進的關係。

平時的**可能是這樣的:

if(write資料庫(data) == true)    else}else
在高負載時期,我們可以降低對一致性的要求。將耗時的「資料落盤」操作降級為「非同步」進行。

if(write分布式快取(data) == true)else
甚至,如果可以的話能做的更徹底,同步到分布式快取也非同步進行。

write本地快取(data);    pushmessage(data); //發出的訊息可以通過集中式的mq、也可以直接寫本地磁碟。return success;
資料庫是系統的最後一座堡壘,非非非常極端的情況下,我們可以把一些「寫資料」操作在「資料庫訪問框架」中給禁用了,讓給所有資源都給到「讀資料」。使得系統從表象上來看至少還是「活著站在那」的,雖然很多功能操作一下就是返回失敗(這不也是實在沒辦法了嘛,面子得要啊,死撐~)。

至此我們聊了做降級的思路以及最常見的一些實現方式,但是真正要把降級最好是乙個任重而道遠的過程。

從方案的角度來說,如果降級的過程需對每個功能/程式逐一進行,那麼理論上10個功能點就可以產生p(10,10)= 3628800種方案。

再從現實的角度來說,流量又是不可**的。某些功能可能這次需要作為level2來看待,下次其實作為level3就夠了。

所以這是乙個需要長期不斷打磨和調優的過程。

讓你的系統「堅挺不倒」的最後乙個大招 降級

也許你對降級已經有了一些認識,認真看完,我想這篇文章可能會給你帶來一些新的收穫 前面兩篇我們已經聊過了 熔斷 如何在到處是 雷 的系統中 明哲保身 這是第一招 和 限流 想通關 限流 只要這一篇 這次我們聊的就是 高可用三劍客 中剩下的 降級 不知道這裡有多少小夥伴接觸過阿里的開放平台。在每次大促的...

魔獸世界是乙個大的浩方

從03年魔獸世界發布以來,我從內測玩到收費,從國服玩到台服,6年時間裡讓暴雪狠狠的賺了一筆,同時也讓他更清楚的認識到了玩家的需要和未來網路遊戲的發展方向。在燃燒遠征和巫妖王之怒的資料片中,暴雪加入了很多小遊戲的元素,坐飛龍轟炸的任務,開坦克打仗的任務等,而在昨天台服更新了3.3之後更提供了fb的跨服...

分享基於silverlight的乙個大檔案上傳控制項

雖然codeplex已經有一些多檔案,帶進度條的上傳控制項,但是覺得都不是很好用,所以基於上面的控制項重新設計了乙個上傳控制項,更好的互動,屬性繫結和管理檔案。1.客戶端使用 mycontrol fileuploadcontrol x name uploader filter 文字檔案 txt re...