摘要:隨著軟體複雜性越來越高,穩定性的保障越來越難,隨著服務規模越來越大,穩定性的重要性越來越高。工程師在設計和開發軟體的時候,要堅持底板思維。控制系統理論認為:系統受到某種干擾而偏離正常狀態,當干擾消除,如果系統的擾動能逐漸收斂並最終恢復正常狀態,則系統是穩定的;反之,系統偏離越來越大,則是不穩定的,所以,穩定性是系統抗干擾和返回平衡狀態的能力。
對於經典的傳遞函式的軟體系統,一般我們講的穩定指的是bibo穩定,即有界輸入有界輸出穩定。乙個系統如果對任意有界輸入得到有界輸出,它就是bibo穩定的。一句話,穩定的系統對於各種輸入需要有符合預期的輸出。
隨著軟體複雜性越來越高,穩定性的保障越來越難,隨著服務規模越來越大,穩定性的重要性越來越高。阿里雲ceo行癲把穩定性比喻成木桶的底板,如果穩定性出問題,則滴水不留,所以,工程師在設計和開發軟體的時候,要堅持底板思維。
我們的軟體需求和計畫很少考慮非功能部分,然而軟體的結構和實現卻有非常大的比重服務於此,這也許是軟體專案計畫經常延期的重要原因。
雖然理論上沒有絕對穩定的系統,但我們依然可以有所作為,使我們設計和開發的系統在生產環境接近穩定執行。
從大的方面講,穩定性保障,可以分成3個部分:
制度紀律
思想之道
實踐之術通過制度去規範操作和行為,通過紀律去約束大家在框架內活動,被證明是保障穩定減少出錯行之有效的方式。
紀律是關鍵,只有持之以恆的遵守制度,才能避免方法和規定淪為空談。
但制度和紀律只是劃出質量底線,只能解決大多數穩定性問題,難以發現一些隱匿的問題,需要配合思想之道和實踐之術,持續改進軟體質量,才能全面保障穩定性。
道是大的層面,它具有全域性性的指導意義,我從眾多的指導思想裡,挑選最重要的兩點:保持簡單和不信任/面向失敗設計,展開來講。
1. 保持簡單
複雜是穩定性的天敵,保持簡單即保持穩定。單一職責,功能清晰即是踐行保持簡單。
把簡單的東西搞複雜很容易,而化繁為簡則堪稱化腐朽為神奇。所以保持簡單並不是低要求,它需要你透過表象洞悉事物本質,用最直接最土味的方式解決問題,做技術的同學有乙個奇怪的癖好,喜歡把自己最近琢磨的東西用到專案中,不然總有錦衣夜行的感覺。
我的建議是「學深用淺」。引入複雜性,一方面要權衡收益,另一方面要警惕損傷,要理解專案開發很多時候是團隊合作,任何複雜性的引入都會對合作者提出更高要求,嚴以律人是危險的,低門檻才是符合人性的。
2. 不信任設計、面向失敗設計
不信任設計又叫零信任設計,和面向失敗的設計有相似之處,其本質都是防禦性程式設計思想。
不信任設計思想假設系統依賴的上下游都不靠譜,假設周圍都是壞人,假設攻擊無處不在。
網路服務需要對客戶端請求引數做嚴格驗證,不僅檢查合法性,也要驗證nan。遊戲開發有一句名言:假設客戶端的資料都是假的。
程序內的函式呼叫大多時候很安全,會有可預期的結果,但如果跨程序呼叫(rpc)的可靠性則會低很多,有可能超時,有可能丟包,有可能失敗,呼叫者必須意識並處理好各種異常情況,是重試?如果重試的話重試多少次?重試之間的間隔應該怎麼確定?請求的上下文怎麼儲存和恢復?
我們要正確理解不信任設計的內涵,避免用力過猛,警惕借面向失敗設計之名行無效程式設計之實,比如已經對客戶端請求資料做了嚴格校驗,在伺服器處理過程中,重複檢驗,比如已經對介面入參判空,在內部呼叫過程中重複判斷。這會降低**濃度,混入大量無效**,損傷可讀性和執行效率,本質上是違背「保持簡單」原則的。
術是區域性層面,它是實踐經驗,牽扯方方面面,難以盡數列舉。
如果以文章寫作模擬軟體開發,謀篇布局相當於設計層面,設計層面要致廣遠,遣詞造句相當於實現層面,實現層面要盡精微。
所謂千里之堤潰於蟻穴,防微杜漸功德無量。
1. 冗餘設計
冗餘設計指留出安全餘量,冗餘包括資料冗餘、計算冗餘、頻寬冗餘。
資料冗餘指乙份資料多個副本,一主多備。
計算冗餘,比如服務例項的qps極限是10k,但實際上我們會按5k跑,這樣,即使出現流量超速增長,我們依然有反應時間。
2. 快速恢復設計(無狀態設計)
網際網路服務很多都是無狀態設計,服務例項只是邏輯的盒子,後面跟著分布式一致性資料庫,這樣能極大簡化設計,即使例項掛了,客戶可以很容易遷移到其他服務例項執行,而有狀態設計則要複雜難搞得多。
3. 容錯、災備
容錯指我們的系統要有一定的錯誤容忍能力,這意味錯誤發生,我們要能查錯、檢錯、避錯、甚至改錯,只要可能,我們就要吞嚥錯誤。
災備這個大家耳熟能詳,主從設計,異地備災,目標都是為了應對各種極限情況。
4. 隔離
隔離本質上就是說如果故障發生了,如果故障發生,而又不能吞嚥,那也應該隔離避免錯誤傳播擴散,千方百計縮小影響範圍,相當於感染新冠要被隔離起來。容器化等技術為隔離提供良好能力支撐。
5. 過載保護
熔斷機制不止軟體設計獨有,**也有,我甚至懷疑軟體的熔斷機制是從**學來的。
系統設計要做好資源耗盡、資源不夠用的情況,如果服務請求超過服務能力,那就應該限流,這應該作為一種配置,或者自動執行的策略。
這個跟地鐵限流差不多,處理不了,那就排隊。
有損的意義就是有損失,有損傷的意思,它是一種思想,是退而求其次,是不得已而為之。
6. 錯誤重試策略,避免流量風暴
如果設計乙個toc服務,在客戶大規模斷連的情況下,客戶會重連,重連失敗再連,如果重連嘗試的頻率不控制好,正常客戶端重連有可能演變成對伺服器的大規模攻擊,打爆一台伺服器,又去滅另一台,這太嚇人了。
可以參考kernel tcp的重連策略,有最大嘗試次數,而且重試間隔是逐漸拉大的。
7 去關鍵路徑、去中心化、避免單點故障
企業不要關鍵先生,關鍵先生會成為瓶頸,軟體也不能把寶壓到乙個地方,去中心化去集中式,沒什麼難理解的。
8 負載均衡
load balance其實就是分擔壓力,lb要避免傾斜,有多種lb演算法,比如rr,比如一致性hash,各有利弊,有興趣可以研究下。
lb不僅限於服務,程序內的多執行緒可能也會需要考慮這個問題。
9 看門狗和心跳機制
可以參考kernel的watch dog,其實就是看護機制,檢測錯誤並努力掰過來。
10 安全編碼最後來讀段經典:《系統化思維導論》一書中引用馮諾依曼的話寫道:如果你觀察一些自動裝置,不論它們是人類設計的還是自然界本來就存在的,你通常會發現,它們的結構很大程度上受控於它們可能失效的方式,以及針對失效所採取的防禦性措施(多少有些效果),說它們能預防失效有點誇張,它們不是能預防失效的,只是被設計成試圖達到這種狀態,這樣至少大部分失效都不會是毀滅性的。所以,根本談不上消除失效,或完全消除失效帶來的影響。我們能嘗試的只是設計一種自動裝置,在大部分失效發生時仍能繼續工作,這種裝置減輕了失效的後果,而不是**失效,大部分人造的和自然界存在的自動裝置,其內部原理都是如此。
點選關注,第一時間了解華為雲新鮮技術~
Android 系統穩定性 ANR(三)
android anr穩定性 android應用程式的所有標準元件全部執行在乙個單一的主線程中,在主線程中所做的任何耗時的操作都有可能造成anr,因為這些耗時的操作會使得主線程沒有機會處理使用者輸入事件或者廣播事件。因此在主線程中執行的任何函式所做的工作都應該盡可能的少,特別是對於activity的...
Android 系統穩定性 ANR(三)
1.4 如何避免anr 1.4.1 anr發生在主線程,不要阻塞主線程 android應用程式的所有標準元件全部執行在乙個單一的主線程中,在主線程中所做的任何耗時的操作都有可能造成anr,因為這些耗時的操作會使得主線程沒有機會處理使用者輸入事件或者廣播事件。因此在主線程中執行的任何函式所做的工作都應...
軟體穩定性判斷的指標和標準
外部標準 1.給客戶帶來的損失 比如資料錯誤,系統宕機。把損失換成金錢,除以此系統本來可以賺的利潤,達到乙個百分比 標準1 客戶損失金額 利潤 說明 得到這個資料可能比較困難,現實有很多情形,我們可以靈活處理。一般的小問題客戶並不去計算損失,只要我們及時的把問題解決了就行了。然而我們總是要付出人力成...