溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點(diǎn)擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

讓你的系統(tǒng)“堅(jiān)挺不倒”的最后一個(gè)大招——「降級」

發(fā)布時(shí)間:2020-07-09 20:51:00 來源:網(wǎng)絡(luò) 閱讀:224 作者:Zachary_Fan 欄目:軟件技術(shù)

如果這是第二次看到我的文章,歡迎文末掃碼訂閱我喲~  

本文長度為4069字,建議閱讀11分鐘。

 

也許你對降級已經(jīng)有了一些認(rèn)識,認(rèn)真看完,我想這篇文章可能會給你帶來一些新的收獲~

 

 

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

 

不知道這里有多少小伙伴接觸過阿里的開放平臺。在每次大促的時(shí)候,阿里都會發(fā)布這樣的一個(gè)公告。

 

讓你的系統(tǒng)“堅(jiān)挺不倒”的最后一個(gè)大招——「降級」

▲2018年雙12的公告內(nèi)容

 

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

 

 

一、什么是「降級」

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

 

什么樣才是效益最大化呢?就像下面這個(gè)例子:

z哥有3個(gè)東西要買,一個(gè)3000的A、一個(gè)700的B、一個(gè)1200的C,對z哥的重要程度A>B>C。但此時(shí),z哥手里只有3000塊錢,你說z哥該怎么選才能把錢花的最多?必然是選A咯。

 

 

根據(jù)28原則,我們知道一個(gè)系統(tǒng)80%的效益是由最核心的20%的功能產(chǎn)出的。剩下的20%效益需要投入80%的資源才能達(dá)到。

 

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

 

當(dāng)然,在實(shí)際的場景中不會降級掉80%的功能這么夸張,畢竟還得為用戶的體驗(yàn)考慮。

 

舉個(gè)電商場景典型的例子,在大促的時(shí)候,最重要的是什么?轉(zhuǎn)化咯~賺錢咯~ 那么這個(gè)時(shí)候如果說「評論」功能占用了很多資源,你會怎么處理?其實(shí)我們可以選擇臨時(shí)關(guān)閉提交評論入口、關(guān)閉翻頁功能等等,讓下單的過程有更多的資源來處理。

 

常見的降級方案表現(xiàn)形式無非以下三種類型。

 

犧牲用戶體驗(yàn)

為了減少對「冷數(shù)據(jù)」的獲取,禁用列表的翻頁功能。

 

為了放緩流量進(jìn)入的速率,增加驗(yàn)證碼機(jī)制。

 

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

 

用通用的靜態(tài)化數(shù)據(jù)代替「千人千面」的動態(tài)數(shù)據(jù)。

 

甚至更簡單粗暴的,直接掛一個(gè)頁面顯示「XX功能在XX時(shí)間內(nèi)暫時(shí)關(guān)閉」。

 

此類方案雖然或多或少降低了用戶的體驗(yàn),但是在某些時(shí)期,有些功能并不是「剛需」。以此換取對系統(tǒng)的保護(hù)是筆劃算的買賣。

 

犧牲功能完整性

還有一些功能是「防御性」的,如果愿意冒險(xiǎn)“裸奔”一段時(shí)間也會帶來可觀的資源節(jié)約。

 

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

 

又或者將原本info、warning級別的日志采集關(guān)閉或者直接不采集,僅采集error以及fault級別的日志。

 

犧牲時(shí)效性

一個(gè)事件發(fā)生后立馬看到效果是一個(gè)很符合「思維慣性」的東西。但是根據(jù)之前的一篇文章(分布式系統(tǒng)關(guān)注點(diǎn)——數(shù)據(jù)一致性(上篇))我們知道,時(shí)效性這個(gè)東西一旦涉及到網(wǎng)絡(luò)傳輸是不存在真正的“實(shí)時(shí)”的。但是為了盡可能快的將處理后的結(jié)果反映到相關(guān)的地方,你會做很多努力。比如庫存的及時(shí)同步。

 

如果在特殊時(shí)期,能夠臨時(shí)降低對時(shí)效性的要求(3秒內(nèi)生效變成30秒生效),也是一個(gè)有不錯(cuò)收益的方案。

 

比如原先在商品頁會顯示當(dāng)前還剩多少個(gè)庫存,現(xiàn)在可以調(diào)整成固定顯示「有貨」。

 

以及將一些原本就是異步進(jìn)行的操作,處理效率放緩,甚至?xí)壕徱欢螘r(shí)間。如,送積分、送券等等。

 

 

講了這么多,降級具體實(shí)施起來要怎么做呢?

 

 

二、「降級」怎么做

主要分為兩個(gè)環(huán)節(jié):定級定序和降級實(shí)現(xiàn)。

 

定級定序

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

 

類似于給日志定義級別一樣,比如我們可以定義1~5五個(gè)級別,1的級別最高,要拼死保護(hù)。5的級別最低最先可以被降級掉。

 

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

 

讓你的系統(tǒng)“堅(jiān)挺不倒”的最后一個(gè)大招——「降級」

 

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

 

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

 

讓你的系統(tǒng)“堅(jiān)挺不倒”的最后一個(gè)大招——「降級」

 

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

 

然后,你可以以每個(gè)程序所支撐的上游程序/功能數(shù)量作為一個(gè)參考標(biāo)準(zhǔn)。比如,同樣是級別5的程序,一個(gè)支撐了上游5個(gè)功能,一個(gè)支撐了10個(gè)功能,很顯然前者的序號應(yīng)該更大,更先被降級。

 

讓你的系統(tǒng)“堅(jiān)挺不倒”的最后一個(gè)大招——「降級」

 

當(dāng)然,根據(jù)所支撐的功能數(shù)量只是一個(gè)「業(yè)務(wù)無關(guān)性」的通用辦法。如果想精益求精,還需要對每個(gè)功能做「作用」上的分析,畢竟不同功能之間的相對重要性還是有所差異的。(這里可以擴(kuò)展了解一下Analytic Hierarchy Process,層次分析法,簡稱AHP

 

 

對了,定級定序的時(shí)候有一點(diǎn)是需要格外注意的:某個(gè)程序所依賴的下游程序的級別不能低于該程序的級別。

 

為什么呢?因?yàn)橐坏┧蕾嚨某绦虮唤导壛?,自然會?dǎo)致其所支撐的所有上游程序不可用。所以,其上游程序的等級再高也是沒有意義的。

 

讓你的系統(tǒng)“堅(jiān)挺不倒”的最后一個(gè)大招——「降級」

 

至此,完成了“排兵布陣”,接下來就是“實(shí)施運(yùn)作”了。

 

降級實(shí)現(xiàn)

首先要制定觸發(fā)機(jī)制。這同熔斷、限流一樣,什么時(shí)候該觸發(fā)「降級」這個(gè)動作也需要依賴提前制定的一些策略。這部分內(nèi)容和前面兩篇(熔斷、限流)類似,無非是接口的超時(shí)率、錯(cuò)誤率,或者系統(tǒng)的資源耗用率等,這里就不重復(fù)展開了。

 

當(dāng)程序發(fā)現(xiàn)滿足了降級條件進(jìn)入「降級模式」后,程序該如何處理請求呢?

 

全局變量 int _runLevel = 3;  //運(yùn)行系統(tǒng)級別,默認(rèn)值5
全部變量 int _runIndex = 7;  //運(yùn)行系統(tǒng)序號,默認(rèn)值9

//以下是一個(gè)level=4、index=8的功能示例。
if(myLevel > _runLevel and myIndex > _runIndex){
    // 進(jìn)入降級模式。
}
else{
    // do something...
}

 

題外話:通過Aop+注解(特性)的方式來做上面的if判斷是一個(gè)爽的事情。

 

 

雖然處理請求的方式有很多,但特別強(qiáng)調(diào)的是,要實(shí)現(xiàn)的降級策略要盡可能的簡單。因?yàn)椤高呺H效應(yīng)」的存在,為了應(yīng)對突發(fā)狀況把事情反而搞復(fù)雜了就得不償失了。

 

那么在實(shí)現(xiàn)部分,如果是前端。我們比較常見的是:

  • 在返回的http報(bào)文中通過Cache-Control的設(shè)置,讓后續(xù)的請求直接走瀏覽器緩存。

  • 頁面中原本需要異步加載的數(shù)據(jù),直接不加載。

  • 禁用部分操作按鈕,甚至直接告知“臨時(shí)關(guān)閉”。

  • 動態(tài)頁面的url通過反響代理切換到靜態(tài)頁面返回。

 

這里面除了禁用按鈕外,大部分事情都可以在接入層,如nginx中處理掉,這樣可以避免對業(yè)務(wù)項(xiàng)目的代碼侵入。

 

如果是后端程序的話,針對「讀」類型的操作,可以將“// 進(jìn)入降級模式”部分代碼寫成下面的樣子:

  • 如果是無返回值方法。默認(rèn)return或者throw一個(gè)異常。

  • 如果是有返回值方法。默認(rèn)返回本地mock的數(shù)據(jù)或者throw一個(gè)異常。

 

后端部分如果有使用一些中間件的話,直接在中間件(rpc、mq代理等)中處理掉是極好的(一般會內(nèi)置一個(gè)fallback接口待實(shí)現(xiàn)),如此也可以避免對業(yè)務(wù)代碼的侵入。

 

最后我們來聊聊后端程序的「寫」問題。

 

緩存是大型系統(tǒng)中的常客,隨著系統(tǒng)規(guī)模越大,為了在性能和成本上尋求更優(yōu),不可避免的會增加復(fù)雜度引入多級緩存。如此就會變成:本地緩存 --> 分布式緩存 --> DB/源服務(wù),這樣的一個(gè)層層遞進(jìn)的關(guān)系。

 

平時(shí)的代碼可能是這樣的:

 

if(write數(shù)據(jù)庫(data) == true){
    if(write分布式緩存(data) == true){
        write本地緩存(data);        
        return success;
    }
    else{
        rollback數(shù)據(jù)庫(data);        
        return fail;
    }
}
else{    
    return fail;
}

 

在高負(fù)載時(shí)期,我們可以降低對一致性的要求。將耗時(shí)的「數(shù)據(jù)落盤」操作降級為「異步」進(jìn)行。

 

if(write分布式緩存(data) == true){
    write本地緩存(data);
    
    pushMessage(data);
    
    //發(fā)出的消息可以通過集中式的MQ、也可以直接寫本地磁盤。
    
    return success;
}
else{
    return fail;
}

 

甚至,如果可以的話能做的更徹底,同步到分布式緩存也異步進(jìn)行。

 

write本地緩存(data);
    
pushMessage(data);

//發(fā)出的消息可以通過集中式的MQ、也可以直接寫本地磁盤。
 
return success;

 

數(shù)據(jù)庫是系統(tǒng)的最后一座堡壘,非非非常極端的情況下,我們可以把一些「寫數(shù)據(jù)」操作在「數(shù)據(jù)庫訪問框架」中給禁用了,讓給所有資源都給到「讀數(shù)據(jù)」。使得系統(tǒng)從表象上來看至少還是“活著站在那”的,雖然很多功能操作一下就是返回失?。?span >這不也是實(shí)在沒辦法了嘛,面子得要啊,死撐~)。

 

 

三、總結(jié)

至此我們聊了做降級的思路以及最常見的一些實(shí)現(xiàn)方式,但是真正要把降級最好是一個(gè)任重而道遠(yuǎn)的過程。

 

從方案的角度來說,如果降級的過程需對每個(gè)功能/程序逐一進(jìn)行,那么理論上10個(gè)功能點(diǎn)就可以產(chǎn)生P(10,10)= 3628800種方案。

 

再從現(xiàn)實(shí)的角度來說,流量又是不可預(yù)測的。某些功能可能這次需要作為level2來看待,下次其實(shí)作為level3就夠了。

 

所以這是一個(gè)需要長期不斷打磨和調(diào)優(yōu)的過程。

 

最后,希望近期的「高可用三劍客」可以作為你了解「高可用」的起點(diǎn),可以先收藏防身(當(dāng)然再分享一下也是極好的:),歡迎后續(xù)一起交流探討~

 

 

 

Question

你曾經(jīng)是否有遇到過什么場景,當(dāng)時(shí)是通過馬上改代碼來「降級」呢?歡迎來吐槽~

 


 

 

相關(guān)文章:

  • 如何在到處是“雷”的系統(tǒng)中「明哲保身」?這是第一招

  • 想通關(guān)「限流」?只要這一篇

  • 分布式系統(tǒng)關(guān)注點(diǎn)——數(shù)據(jù)一致性(上篇)

 


 

 

作者:Zachary

出處:https://www.cnblogs.com/Zachary-Fan/p/degradation.html 

 

?關(guān)于作者:張帆(Zachary,個(gè)人微信號:Zachary-ZF)。堅(jiān)持用心打磨每一篇高質(zhì)量原創(chuàng)。歡迎掃描下方的二維碼~。

定期發(fā)表原創(chuàng)內(nèi)容:架構(gòu)設(shè)計(jì)丨分布式系統(tǒng)丨產(chǎn)品丨運(yùn)營丨一些思考。

 

如果你是初級程序員,想提升但不知道如何下手。又或者做程序員多年,陷入了一些瓶頸想拓寬一下視野。歡迎關(guān)注我的公眾號「跨界架構(gòu)師」,回復(fù)「技術(shù)」,送你一份我長期收集和整理的思維導(dǎo)圖。

如果你是運(yùn)營,面對不斷變化的市場束手無策。又或者想了解主流的運(yùn)營策略,以豐富自己的“倉庫”。歡迎關(guān)注我的公眾號「跨界架構(gòu)師」,回復(fù)「運(yùn)營」,送你一份我長期收集和整理的思維導(dǎo)圖。

 讓你的系統(tǒng)“堅(jiān)挺不倒”的最后一個(gè)大招——「降級」


向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI