軟體架構 解構高可用

2022-09-07 11:36:10 字數 3817 閱讀 7284

控制系統理論認為:

系統受到某種干擾而偏離正常狀態,當干擾消除,如果系統的擾動能逐漸收斂並最終恢復正常狀態,則系統是穩定的,反之,系統偏離正常越來越大,則是不穩定的。所以,穩定性是系統抗干擾和返回平衡狀態的能力。

對於經典的傳遞函式的軟體系統,一般我們講的穩定指的是**「bibo穩定」,即有界輸入有界輸出穩定**。乙個系統如果對任意有界輸入得到有界輸出,它就是bibo穩定的。一句話,穩定的系統對於各種有效輸入需要有符合預期的輸出,它應該像不倒翁一樣。

隨著服務規模越來越大,穩定性的重要性越來越高,隨著軟體複雜性越來越高,穩定性保障越來越難。阿里雲ceo行癲把穩定性比喻成木桶的底板,如果穩定性出問題,則一滴水也裝不下,所以,工程師在設計和開發軟體的時候,要堅持底板思維。

我們的軟體需求和計畫很少考慮非功能部分,然而軟體的結構和實現卻有非常大的比重服務於此,這也許是軟體專案計畫經常延期的重要原因。

雖然理論上沒有絕對穩定的系統,但我們依然可以有所作為,使我們設計和開發的系統在生產環境接近穩定執行。

從大的方面講,穩定性保障,可以分成3個部分:

通過制度去規範操作和行為,通過紀律去約束大家在框架內活動,被證明是保障穩定的第一道防線,也是減少出錯行之有效的方式。

紀律是關鍵,只有持之以恆的遵守制度,才能避免方法和規定淪為空談。

但制度和紀律只是劃出質量底線,只能解決大多數穩定性問題,難以發現一些隱匿的問題,需要配合思想之道和實踐之術,持續改進軟體質量,才能全面保障穩定性。

道是大的層面,它具有全域性性的指導意義,我從眾多的指導思想裡,挑選最重要的兩點:保持簡單和不信任(面向失敗)設計,重點展開。

複雜是穩定性的天敵,保持簡單即保持穩定。單一職責,功能清晰即是踐行保持簡單。

把簡單的東西搞複雜很容易,而化繁為簡則堪稱化腐朽為神奇。所以保持簡單並不是低要求,它需要你透過表象洞悉事物本質,用最直接最土味的方式解決問題,做技術的同學有乙個奇怪的癖好,喜歡把自己最近琢磨的東西用到專案中,不然總有錦衣夜行的感覺。

我的建議是「學深用淺」。引入複雜性,一方面要權衡收益,另一方面要警惕危害,要理解專案開發很多時候是團隊合作,任何複雜性的引入都會對合作者提出更高要求,嚴以律人是危險的,低門檻才是符合人性的。

不信任設計又叫零信任設計,和面向失敗的設計有相似之處,其本質都是防禦性程式設計思想。

不信任設計思想假設依賴的上下游都不靠譜,假設周圍都是壞人,假設攻擊無處不在。

內部不可信,外部不可信。

措施:邊界控制 + 身份認證 + 核查校驗

網路服務需要對客戶端請求引數做嚴格驗證,不僅檢查合法性,也要驗證nan。遊戲開發有一句名言:假設客戶端的資料都是假的。

程序內的函式呼叫大多時候很安全,會有可預期的結果,但如果跨程序呼叫(rpc)的可靠性則會低很多,可能超時,可能丟包,也可能失敗,呼叫者必須意識並處理好各種異常情況,是重試?如果重試的話重試多少次?重試之間的間隔應該怎麼確定?請求的上下文怎麼儲存和恢復?

我們要正確理解不信任設計的內涵,避免用力過猛,警惕借面向失敗設計之名行無效程式設計之實,比如已經對客戶端請求資料做了嚴格校驗,在伺服器處理過程中,重複檢驗,比如已經對介面入參判空,在內部呼叫過程中重複判斷。這會混入無效**,降低**濃度,損傷可讀性和執行效率,除了一點心理安慰並不起實際作用,本質上是違背「保持簡單」原則的。

plus:谷歌的零信任架構的本質是以身份為基石的動態可信訪問控制。

術是區域性層面,它是實踐經驗,牽扯方方面面,難以盡數列舉。

如果以文章寫作模擬軟體開發,謀篇布局相當於設計層面,設計層面要致廣遠,遣詞造句相當於實現層面,實現層面要盡精微。

所謂千里之堤潰於蟻穴,防微杜漸需要一以貫之的執行。

冗餘設計指留出安全餘量,不滿負荷跑,冗餘包括資料冗餘、計算冗餘、頻寬冗餘。

資料冗餘指乙份資料多個副本,一主多備。

計算冗餘,比如服務例項的qps極限是10k,但實際上我們會按5k跑,這樣,即使出現請求超速增長,依然有反應時間。

網際網路服務很多都是無狀態設計,服務例項只是邏輯的盒子,後面跟著分布式一致性資料庫,這樣能極大簡化設計,即使例項掛了,客戶可以很容易遷移到其他服務例項執行,而有狀態設計則要複雜難搞得多。

遊戲伺服器經常有共享儲存的設計,把玩家需要存檔的資料放在shm,這樣即使遊戲伺服器crash,也能快速恢復,不丟資料。

容錯指我們的系統要有一定的錯誤容忍能力,這意味錯誤發生,我們要能查錯、檢錯、避錯、甚至改錯,只要可能,我們就要吞嚥錯誤,而不傳播錯誤。

災備這個大家耳熟能詳,主從設計,異地備災,目標都是為了應對各種極限情況,實現服務高可用。

隔離就是說如果故障發生了,而又不能吞嚥,那應該隔離避免錯誤傳播擴散,避免雪崩,千方百計縮小影響範圍,提高系統整體可用率,就像感染新冠要被隔離起來乙個道理。

隔離設計並非軟體行業獨創,它是借鑑於造船行業的船艙設計。

隔離又分兩種:

功能隔離和使用者隔離並非互斥,可結合起來使用,實施隔離需要兼顧安全性、效率、資源利用率,模組顆粒度。

另外,容器化等技術為隔離提供良好能力支撐。

系統過載 = 系統處理能力 < 服務請求量。通常可以用qps、請求處理的平均時延等去評估系統處理,系統瓶頸指系統中最先接近極限的資源,一般系統資源包括cpu,記憶體,io。

過載保護方案分為發生前的過載預防,發生時的過載處置,發生後的過載恢復。

過載預防包括壓測,監控,lb,前端預防等,過載恢復一般指假死,宕機後的服務重啟,狀態恢復等,而過載處置包括:

常見的限流演算法有:計數器、漏桶和令牌桶演算法。

比如直播業務在頻寬有限的情況下,應該降低位元速率減少清晰度,而不應該拒絕服務。

如果設計乙個toc服務,在客戶大規模斷連的情況下,客戶會重連,重連失敗再連,如果重連嘗試的頻率不控制好,正常客戶端重連有可能演變成對伺服器的大規模攻擊,打爆一台伺服器,又去滅另一台,這太嚇人了。

重試退避功能用於計算延遲的演算法,在退避階段,從第一次到最後一次重試的延遲時間計算方法(1)線性的(2)算術的(3)幾何的(4)指數的:

可以用指數回退方式重試,也可以參考kernel tcp的重連策略,有最大嘗試次數,而且重試間隔是逐漸拉大的,避免流量風暴。

企業不要關鍵先生,關鍵先生會成為瓶頸,軟體也不能把寶壓到乙個地方,去中心化去集中式,就是降低風險。

去中心化在某種程度上來說,可謂是的網際網路世界的共產主義化,區塊鏈即是去中心化思想的最好體現。

load balance其實就是分擔壓力,lb要避免傾斜,比如對username做負載均衡,可能c開頭的使用者遠比v開頭的使用者多,從而導致傾斜。

有多種lb演算法,比如rr,比如一致性hash,各有利弊,有興趣可以研究下。

lb不僅限於服務,程序內的多執行緒可能也會需要考慮這個問題。

降級可以是自動降級或人工降級,可以是讀服務降級或寫服務降級。

降級發生場景:

可以參考kernel的watch dog,其實就是看護機制,檢測錯誤並努力掰過來。

c相關的規則要少一些,我順手列舉一些。

最後來讀段經典:

《系統化思維導論》一書中引用馮諾依曼的話寫道:如果你觀察一些自動裝置,不論它們是人類設計的還是自然界本來就存在的,你通常會發現,它們的結構很大程度上受控於它們可能失效的方式,以及針對失效所採取的防禦性措施(多少有些效果),說它們能預防失效有點誇張,它們不是能預防失效的,只是被設計成試圖達到這種狀態,這樣至少大部分失效都不會是毀滅性的。所以,根本談不上消除失效,或完全消除失效帶來的影響。我們能嘗試的只是設計一種自動裝置,在大部分失效發生時仍能繼續工作,這種裝置減輕了失效的後果,而不是**失效,大部分人造的和自然界存在的自動裝置,其內部原理都是如此。

高可用 架構

不要把雞蛋都放在同一籃子裡 標準 1 正常情況下,使用者無論訪問哪乙個地點的業務系統,都能夠得到正確的業務服務。2 某個地方業務異常的時候,使用者訪問其他地方正常的業務系統,能夠得到正確的業務服務。與 活 對應的是字是 備 備是備份,正常情況下對外是不提供服務的,如果需要提供服務,則需要大量的人工干...

grafana高可用架構

grafana的高可用主要通過這兩項類保證 alerting目前還不支援高可用配置 database either mysql postgres or sqlite3 it s your choice type mysql host 192.168.99.100 3306 name grafana ...

Redis高可用架構

官網 解壓 tar zxvf redis 5.0.5.tar.gz 切換目錄 cd redis 3.2.9,執行編譯命令 make 切換到 redis 3.2.9 src 目錄執行命令 vim redis.conf protected mode no bind 127.0.0.1 daemonize...