1. 程式人生 > >構建可靠系統的原則與實踐

構建可靠系統的原則與實踐

隨著阿里技術的發展,我們的技術系統越來越成為社會的基礎設施,對於這些系統的可靠性要求也就越來越高。但是實際上很多的基礎的產品和系統確仍然會出現一些穩定性問題,那麼如何才能構建可靠的系統呢?是不是制定非常嚴格而細緻的規則就可以做出可靠的系統呢?

航空業的教訓

在回答這個問題之前,我們先來看看對於系統可靠性要求非常高的航空業是怎麼做的?美國的FAA是在航空安全領域事實上的權威,為了保證航空器的安全,FAA制訂了非常詳細而複雜的航空器認證規則,而這些規則是否就保證了航空器的安全了呢?

讓我們來了解一下最近的兩起空難:

2019年3月10日,衣索比亞航空ET302航班在起飛六分鐘後墜毀,飛機上載有149名乘客和8名機組人員。


2018年10月29日,印尼獅航JT610航班在起飛後約十分鐘墜毀,飛機上載有181名乘客,和8名機組人員。

幾百條鮮活生命的消逝,這是多麼嚴重的後果啊!究竟是什麼原因導致了這樣的災難呢?

這兩起空難的共同點是都是波音的737MAX機型,並且都是在起飛後不久發生的空難。那麼這個背後的原因是什麼呢?雖然官方的調查還沒有結束,但是民間的分析指向了同一個原因,那就是這款機型的設計問題。

上圖展示了Boeing 737 MAX的CFM LEAP引擎,值得注意的是和一般民航飛機不同的是,引擎的上沿和機翼平面幾乎齊平。為什麼會這麼設計呢?這是因為波音737系列最早是上世紀60年代設計的,當時的引擎的直徑小很多,外形更加細長,而機翼的高度是和引擎直徑相匹配的。但是隨著技術的發展,更新更省油的引擎直徑變得越來越大,這時候原來的機翼高度無法滿足更大直徑引擎的安裝空間,要想調整機翼的高度則需要改變起落架的設計,改變起落架的設計則需要改變起落架收起時相關機體位置的設計,而機體設計的變化會帶來更多的變化從而會被FAA認為是一款全新型號的飛機,而全新型號的飛機則需要經歷完整的FAA認證流程,會帶來巨大的時間和經濟成本。為了避免這樣的成本波音選擇了將引擎前移並且提升高度,但是這樣帶來了另外一個問題,由於空氣動力學方面的原因,飛機會變得靜不穩定,特別是在起飛階段,引擎的推力會導致飛機迎角過高進入危險的失速狀態。為了迴避這個問題,波音引入了一個自動控制程式MCAS,通過讀取迎角感測器的資料判斷飛機是否迎角過高,如果過高的話自動控制飛機降低迎角,從而保證飛機的安全。

那麼這麼一套保證飛行安全的系統和空難有什麼關係呢?事實上MCAS系統工作得非常好,根據波音自己的統計,Boeing 737 MAX系列已經完成了數十萬次的安全起降。但是問題在於當感測器工作不正常時,MCAS有可能會根據錯誤的迎角資料做出錯誤的判斷和動作,也就是在不應該降低迎角的時候降低迎角,導致飛機直衝地面。

一起後果擴大的故障

回到我們的工作中,前不久我們碰到了一起系統故障,其過程有一定典型的意義,為了描述方面,這裡隱去一些具體細節,簡單說一下故障的過程。
開始的時候,由於某些原因導致快取命中率有所下降,而快取命中率下降導致了資料庫load升高,而資料庫load升高以及可能的慢SQL導致了部分請求在獲取DB connection的時候超時,從而引發了exception。當exception發生的時候,為了保證系統的可用性,系統邏輯進入了一段兜底邏輯,而這段兜底邏輯在特定的條件下產生了錯誤的返回,從而導致線上髒資料,而這些髒資料帶來了業務資損和大量的人工訂正資料的成本。

這個故障處理的過程並不是重點所以不再贅述,我們要問的是為什麼一個簡單的exception會導致這麼嚴重的後果呢?

兩個事例的共同點

如果我們仔細去觀察上述兩個事例,我們會發現其中有如下幾個共同點:

  • 為了好的目的而引入了非常簡單的備用邏輯直接保證“效果”
  • 這些備用邏輯在絕大部分情況下都能正常工作
  • 但是在極端情況下這樣的邏輯失效了,並且產生了嚴重的後果

換句話說,系統設計者在嘗試用非常簡單的邏輯去解決一個實際上覆雜的問題,雖然實際上並沒有完全解決問題,但是因為這樣的邏輯能夠通過大量的測試(或者合規檢查),所以系統設計者“假定”問題得到了解決,從而放心地應用到了生產環境。

那麼一個非常複雜的問題是否真的能夠通過一個簡單巧妙的辦法解決嗎?

沒有銀彈

在系統設計領域,我們通常會把問題的複雜性分為兩類,分別是偶得複雜性,實質複雜性。

偶得複雜性 Accidental Complexity

所謂偶得複雜性是指由開發者自己在嘗試解決問題時引入的複雜性挑戰,一般而言是由解決問題的方法和手段帶來的,對於特定的問題,不同的方法會帶來不同的偶得複雜性。

實質複雜性 Essential Complexity

所謂實質複雜性是由事務本身所決定的,和解決方法無關。

對於偶得複雜性,通過變換解決辦法是有可能用簡單的辦法來解決的,但是對於實質複雜性,我們是無法通過改變手段來解決的,而必須採用相應複雜的方法來解決問題。換句話說對於實質複雜的問題,不要指望有銀彈

上述事例中,實際的環境和問題是存在比較大的實質複雜性的,然而我們卻試圖通過一些非常簡單的邏輯去解決問題,從而帶來了嚴重的後果。

快速失敗 Fail Fast

那麼要想防止這類問題,設計高可靠的系統要怎麼做呢?
這裡我想介紹一條反直覺的軟體設計原則,快速失敗(Fail Fast):

In systems design, a fail-fast system is one which immediately reports at its interface any condition that is likely to indicate a failure.

這是一條反直覺的原則,大部分人聽說這條原則的第一反應是這樣不是讓系統變得更加脆弱了嗎?

實際上並不是,原因在於我們不能停留在某一次的失敗(failure),而是需要觀察完整的過程,如下圖所示:

當問題發生時,系統立即停止工作,由人工介入找到並以合理的方式解決根本的問題,然後系統恢復運作。通過這樣的選擇,我們就能夠更早更容易地暴露問題,每當系統發生問題之後,真正的根因會更快得以解決,所以最後我們就能得到一個更加可靠的系統。

需要說明的是,快速失敗不是說系統設計不處理任何問題到處失敗,而只是在面對essential complexity的時候,不要嘗試用一個簡單粗暴的方案去解決,要麼就用一套合理的機制設計去解決它,要麼就fail fast把控制權交給系統上層決策,通常來說最終可能會迴歸到人,由人來分析和處理問題。

根據實際的工作經驗,我還發現一個有意思的現象,很多系統的設計者往往高估一些能輕易想到的問題的嚴重性,而低估那些想不到的問題的嚴重性。上述的軟體系統故障的例子中,如果異常往外丟擲,問題的後果可能僅僅是某些操作人員的部分操作失敗,使用者可能會重試,也可能會開工單把問題反饋上來。只要我們處理工單的同學及時響應並且解決根本問題,這個問題就不會演變成一個比較嚴重的問題。但是不丟擲異常通過備用邏輯來兜底一旦失敗,會導致比較嚴重的後果。如果系統的設計者能夠認真衡量和計算這些後果的差別,就會做出更加合理的選擇。

當然還有一點就是快速失敗會把更多數量的問題暴露在使用者面前,讓使用者在心理層面有不好的影響,但是需要注意的是不暴露問題不等於解決問題,暴露問題只是讓大家看到了問題而已。為了更好更早地暴露問題,一方面我們需要引入更完備的測試防止問題進入生產環境,另外一方面也需要引導系統使用者以更加客觀實際的心態來接受系統中的問題。

不要重複自己 Don't Repeat Yourself

和構建穩定系統相關的另外一條原則是軟體工程中常說的DRY原則,也就是:

Every piece of knowledge must have a single, unambiguous, authoritative representation within a system.

這一條和穩定系統的關係在於,通過合理的複用設計,能夠大幅度提高系統的可測性,降低除錯問題的難度,提高系統的可維護性,背後的邏輯還是比較簡單的,這裡不再贅述。

如何實踐上述原則

那麼要想實踐上述原則構建可靠的系統需要注意哪些方面呢?
結合自己的工作經驗,我認為主要是這麼幾個方面:

所有的原則都是有代價的

世界上沒有免費的午餐,借用之前Choice課程老師的一句話,堅持價值觀都是有代價的,我們也可以說
堅持原則都是要付出代價的。
這裡的代價包括工作量,短期結果,解決問題的難度,帶來的專案風險等等,系統的設計者需要做出合理的權衡,付出一定的代價才可能應用上述的原則。

刨根問底,5 whys找到根因

當問題發生時,最重要的事情在於找到問題的根因,只有我們解決了根本的問題,系統才會真正變得健壯起來,否則都只是假象。我們可以用 5 whys 的辦法來找到問題的根本原因。

迴歸測試保障

個人認為自動化迴歸測試相當於汽車的安全帶,我們需要構建覆蓋度高的自動化迴歸測試保障體系,從而更早更好地發現問題,減少對於終端使用者的衝擊,把問題扼殺在萌芽狀態。

讓團隊養成好的習慣

不管是一個開發者,還是一個開發團隊,堅持原則並不是臨時起意,而需要成為習慣。只有把原則變成習慣的個人或者團隊,才能夠真正貫徹這些原則。所以平常工作中某些看起來沒有必要的堅持原則,實際上有助於習慣的養成,而當原則成為了團隊的習慣,這些原則才能在需要的時候得以實踐,獲得回報。

不要把fail fast曲解為快速試錯

可能有人會認為fail fast就是快速試錯,也就是不斷嘗試,碰到正確的為止。需要強調的是快速失敗需要很好的設計和機制保證。

後記

以上是我對於構建可靠系統的思考與實踐總結,最近做了一次分享但是感覺沒有講好所以寫下來,歡迎討論和拍磚。

參考文件

  1. Fail Fast
  2. Software Won't Fix Boeing's 'Faulty' Airframe
  3. Gregory Travis's article about Boeing 737 MAX

作者:行易

原文連結

本文為雲棲社群原創內容,未經