DDD不夠好用,你需要學習如何進行彈性軟件系統設計

關鍵要點

  • 當今的分佈式系統環境必須採用彈性軟件設計。
  • 關鍵挑戰不在於編碼,而在於“外圍”。
  • 做好分佈式其實很難,大多數人都嚴重低估了它的難度。
  • 恰當的功能設計是構建健壯的分佈式系統的關鍵,但人們卻知之甚少。
  • 在公司中引入彈性軟件設計的主要挑戰是如何建立意識和可持續性。

寫這篇文章的起因是我在2018年GOTO柏林大會上所做的演講,我在演講中分享了在進行彈性軟件設計時會面臨哪些挑戰。我將簡要地介紹彈性軟件設計的“why”和“what”,中間部分是我近年來經常遇到的挑戰,最後,我添加了一些關於如何在組織中實現彈性軟件設計的最佳實踐。閱讀完本文之後,希望你能夠更好地瞭解彈性軟件設計所面臨的挑戰,並知道如何解決這些問題。

什麼是彈性軟件設計,爲什麼它很重要?

彈性軟件設計(Resilient Software Design,簡稱RSD)是一個無法用一兩句話解釋清楚的概念——有時候很難向習慣於“電梯遊說”(在很短時間內說清楚一個問題)的人解釋這個概念。儘管如此,我仍然試着儘可能簡短地解釋我所知道的RSD,一個是“why”,一個是“what”。

讓我先從“why”開始。通常,我們試圖通過系統來實現某種商業價值:賺錢或者讓客戶滿意。顯然,只有當系統在生產環境中看用時,我們纔有可能實現這一價值。這一直以來都是這樣的。

但是,現在有所不同的是,幾乎每個系統都是分佈式的。系統之間相互通信,並且系統本身也可能被分成幾個部分,而這些部分進一步被拆分,並以此類推。微服務、移動計算和物聯網的發展使得協作系統之間的連接變得更加複雜,將這些系統的開發提升到新的水平。

系統及其部件之間相互交互所需的遠程通信會引入一些故障模式,這些故障模式只存在於跨進程邊界的情況,不會在進程內部出現。如果我們忽略它們的存在,這些故障模式,例如非響應性、等待時間、不完整或無序消息將在應用程序級別上引起所有類型的非預期故障。換句話說,如果你需要一個健壯高可用的系統,就不應該忽略分佈式所帶來的影響。

這讓我想到了RSD的“what”:我傾向於將彈性軟件設計定義爲“在理想情況下,如果發生意外故障(由分佈式的非確定性行爲造成的),用戶根本不會注意到,或者用戶至少可以繼續使用應用程序已定義範圍的部分功能(即服務的優雅降級)”。

請注意定義中的“已定義”一詞。這意味着,計劃在發生意外情況時該做些什麼,這個與你通常在不採用彈性軟件設計時遇到的意外系統行爲有很大不同。

彈性軟件設計的任務

我的旅程通常從在代碼級別設計和實現彈性開始。但隨着時間的推移,我意識到,在代碼層面實現彈性是最容易的部分,實際的挑戰其實是在其他方面。

雖然在事後看來,這並不足爲奇(大型項目的問題從來都不是在編碼層面),但我不得不承認,我剛開始還是感到有些奇怪。你只有長期接觸這個問題,纔有可能清楚地瞭解這些挑戰。因此,我在“彈性軟件設計的7個任務”演講中分享了我的一些經驗,其中每個“任務”代表了我遇到過的一個挑戰。以下是從我的演講中挑選出來的挑戰。

  1. 瞭解RSD的“業務案例”。作爲一名軟件工程師,如果你嘗試開發新的東西,通常會被問及相關的業務案例是什麼。雖然這是一個無可厚非的問題,但如果被應用在RSD上,就會導致方向跑偏,因爲RSD不是爲了賺錢,而是爲了不損失錢。儘管如此,定義彈性預算仍然是有必要的,你可以看一下如果系統變得不可用會有哪些即時的損失,以及由於累積效應(例如感到厭煩的客戶會增加你的流失率)導致的更頻繁的不可用性造成的長期損失。通過這種方式,我們可以將RSD嵌入到一個理智的經濟框架中。
  2. 瞭解分佈式系統的非確定性行爲及其後果。問題是分佈式系統不僅難以駕馭,而且難以理解。遠程通信爲系統行爲添加了概率性因素。不幸的是,我們的大腦無法輕易地處理概率性行爲。此外,幾乎所有的IT教育或培訓都是以進程內交互爲前提,在這些環境中,我們面臨的是確定性的行爲,導致大多數人對分佈式不甚瞭解。我也不知道有哪些簡單的分佈式解決方案(我其實認爲不存在這樣的解決方案)。也許在我們的IT教育中添加更多與分佈式系統相關的教材可能會有所幫助。數以百計的計算機科學論文已經清楚地告訴我們,進程內的東西一旦變成分佈式的,即使再簡單也會變得很難,甚至是不可能的。但並不是所有人會去閱讀這些資料。然後有些人說,我們應該將遠程通信問題留給基礎設施去解決,讓應用工程師不受干擾。過去的很多分佈式框架都遵循了這一理念——事實證明,這隻適用於非常小的系統,總體來說並不是可行的解決方案……
  3. 避免“100%可用”的陷阱。這與上一個挑戰有關,但影響範圍要小得多。由於典型的確定性思維,人們(無論是IT人員還是非IT人員)都傾向於假設他們連接的所有系統的可用性都可以達到100%。你可以在需求、設計和代碼方面看到這種隱含的假設。並不是人們有不良意圖,也不是他們粗心大意,只是他們忘記了一些東西。在分佈式系統中,問題不在於系統是否會發生故障,而是會在什麼時候發生故障。可用性始終會小於1(或者說小於100%)。因此,我們需要小心100%可用性的陷阱,並檢查我們的要求、設計和代碼,避免掉入這個陷阱。
  4. 建立OpsDev反饋閉環。在很多公司,我們仍然看到開發和運維之間存在巨大的屏障,甚至已經觸及C級人員。造成這種局面有一定的原因,同時也給RSD帶來了一個大問題。彈性需要在應用程序層面實現,也即在開發中。但是,你只能通過運維來衡量實際的彈性效果。此外,在運維中,你會檢測到需要由開發來處理的應用程序缺陷。但是如果你在Dev和Ops之間有一堵大牆,就會破壞這個重要的反饋閉環。開發人員盲目地實施他們的彈性舉措,而運維發現的問題卻得不到修復。因此,無論你是使用DevOps或SRE等既定方法,還是使用自定義的方法,都需要建立反饋閉環。
  5. 正確的功能設計。如果分佈式功能在設計方式上出了問題,那麼即使再好的彈性措施也無法幫你構建出健壯的系統。問題出在這裏:假設你在服務之間創建了緊密的功能依賴(“強耦合”)。如果被依賴的服務變得不可用,那麼所有依賴這個服務的服務也將變得不可用,因爲這些服務需要藉助被依賴服務的業務邏輯來完成自己的任務。遺憾的是,我們學到的幾乎所有與設計系統相關的技術,即如何劃分功能,都會導致強耦合,因爲它們側重於進程內設計,而進程內設計的可用性不受這種耦合性的影響。因此,我們需要重新學習分佈式系統的功能設計,重點是降低功能耦合——這與進程內的低耦合不同。我將在下一節深入探討這個主題。
  6. 瞭解應該使用哪些模式以及如何合理地組合它們。在你學習完新模式後,總想着去用它們。問題是,使用彈性模式是要付出代價的。它們通常會增加實現和運維成本。更重要的是,它們增加了解決方案的複雜性,而複雜性是健壯性的敵人。解決方案越複雜,就越難以理解,意外故障給健壯性帶來不利影響的可能性也就越大。因此,關鍵在於不要使用太多的模式,而是要在彈性和複雜性之間找到一個平衡點。
  7. 不要因爲技術的更新換代每幾年就淘汰積累起來的社區知識。這不是RSD特有的,它適用於整個IT行業。作爲一個社區,我們傾向於每隔幾年就將集體智慧淘汰,然後從頭開始。我們傾向於忽視我們已經知道的東西,然後尋找下一個被炒作起來的銀彈,以此來解決我們的問題,而不是像其他工程學科一樣建立和維護經過驗證的知識體系。同樣,這不僅限於RSD,但我們現在可以觀察它們,因爲大多數RSD概念不是新東西,其中一些已經存在了幾十年了。說實話,我也不知道該如何解決這個問題。因此,我能夠想到的最好的事情是提醒人們要注意這個問題,並希望如果有足夠多的人意識到這一點,最終將成長爲一個真正的工程學科。

當然,還有其他更多的挑戰,但從我的角度來看,這些是最應該引起我們注意的。

基於彈性軟件設計創建更健壯的應用程序

根據我的經驗,理解分佈式系統以及如何進行好的功能設計是創建健壯應用程序的最大障礙。因此,讓我們更深入地探討這兩個主題。

理解分佈式故障模式的含義是非常困難的。單進程系統中一些很簡單的事情到了分佈式系統中有會變得非常困難,甚至是不可能的,而且基礎設施無法爲應用程序隱藏掉所有這些影響。另一方面,大多數(如果不是全部)大學和大學後的IT教育都是基於本地計算。此外,試圖掌握分佈的非確定性影響對我們的大腦來說並不是一件容易的事。

根據我的經驗,IT領域之外的大多數人幾乎不可能真正理解分佈式,因爲他們把計算機理解爲“可以完成人類佈置的任務的機器”,教會他們有關分佈式計算的概念和所面臨的挑戰需要很長時間——我們通常沒有那麼多時間。

但其實對大多數開發人員來說也是非常困難的。開發人員在面對不可用的分佈式系統時,他們通常也會不知所措。由於他們的IT教育完全忽略了分佈式系統,他們甚至會避免處理與分佈式有關的問題。這導致在設計和實現系統時忽略了分佈式的影響,而這反過來讓系統變得既脆弱又慢。

我之前說過,我不知道這個問題有什麼簡單的解決方案,我其實認爲並不存在所謂的簡單的解決方案。我能做的就是建議在我們的IT教育(大學期間和大學之後)中增加更多有關分佈式系統設計的課程,因爲我們的系統環境變得越來越分散,我們需要更好地瞭解設計和編碼的實際效果。

另一個巨大的阻礙是功能設計。如果功能傳播的方式是錯誤的,最終只會得到一個脆弱的系統。舉個簡單的例子:服務A接收外部請求,爲響應該請求,它需要來自服務B的一些信息,這也就是所謂的在服務之間傳播功能。如果服務B被關閉,服務A就無法響應外部請求。

這就是所謂的級聯故障。彈性軟件設計的主要任務之一是避免級聯故障。通常,你可以使用簡單的超時檢測機制或斷路器來檢測服務B是否已關閉,然後回退使用服務A的備份計劃。但由於功能在服務之間傳播,不可能有備份計劃,即斷路器只會讓級聯故障可見,不會提供任何繞過它的方法。

這只是其中的一個例子,類似的情況還有很多。如果你將通常的“設計最佳實踐”應用於分佈式系統,通常會出現這類問題。在給定的示例中,服務B是“可重用服務”。可重用性是單進程的理想屬性,但它也會帶來非常強的耦合性,在跨進程的環境中表現出非預期的特性。

在過去,如果我們的功能設計出現錯誤,到最後系統會變得難以維護——這已經夠糟糕的了。但是,在分佈式系統中,糟糕的功能設計在運行時就會體現出脆弱性、不可靠和性能問題,這個更糟糕。問題是大多數有關如何做出“正確設計”的建議只適用於進程內設計。如果將這些建議應用在分佈式系統上,大多數都無法正常工作。

我從過去的經歷中學到的是,我們需要重新學習如何設計系統,即如何在分佈式環境中傳播功能。

然後,大多數人會提到領域驅動設計(或簡稱“DDD”),但根據我的經驗,這也不是靈丹妙藥。不要誤會我的意思,實際上,DDD爲更好的設計提供了很多非常好的建議。但是當談到分佈式系統的設計時,單靠DDD是不夠的,它還缺少了一些額外的建議。好的方面是:據我所知,人們正在嘗試擴展DDD的原始思想,加入分佈式系統因素。因此,我對這一領域的未來發展非常期待。

發展構建彈性應用程序所需的技能

如果你想將RSD引入到你自己的公司,你可能會要求制定一個可以達到最佳效果的計劃。根據我的經驗,並不存在完美的計劃。我的建議是實現通用的“意識—能力—可持續性”模式。

首先,瞭解爲什麼需要RSD以及如何將其傳達給不參與軟件開發的人員。這涉及理解和接受分佈式系統的不可用性(包括避免“100%可用性”陷阱)和彈性軟件設計的業務案例。此外,你還需要學習如何在不使用深奧的IT知識的情況下將其傳達給人們。即使你知道需要通過RSD來構建健壯的系統,但卻不能與你的經理或你的企業主討論它,並幫助他們更好地理解這個主題,然後做出正確的決策,那麼這一切將無濟於事。

獲得知識可能是最容易的部分。同時,還可以找到一些有關這個主題的資源和培訓——只需要注意與分佈式系統或微服務相關的會議的研討會部分,或者從閱讀文末參考部分提供的兩本書開始。當然,你需要在工作中應用它們。再強調一下,做出正確的功能設計是一項艱鉅的任務,但彈性模式本身相對容易學習和應用。

要建立可持續性,首先需要一個有效的OpsDev反饋循環。如果沒有這種循環,任何彈性倡議都將註定失敗,因爲你的彈性度量在實踐中缺少了反饋。

此外,你可能希望建立混沌工程計劃。混沌工程不僅有助於揭示系統缺陷,它還通過持續、可控的學習(瞭解系統的健壯性並進一步提高系統健壯性)幫你實現可持續的彈性。

“混沌工程”這個詞有點容易被誤解,它不是爲了製造混亂,而是爲了避免混亂。在混沌工程中,你可以設計受控的實驗,以便更好地瞭解系統的實際健壯性以及需要做出哪些額外的彈性措施。混沌工程師總是小心翼翼地控制實驗潛在的影響範圍,並在執行實驗之前與所有受影響的人進行溝通。

它從一個假設開始,例如“如果我們切斷與此服務器的連接,將發生自動故障轉移,最終用戶不會察覺到任何差異”。然後,與受影響的開發人員和運營人員討論該假設。假設是有效的嗎?我們怎麼測試它呢?我們如何衡量正確性?如果我們錯了,怎樣才能以安全的方式停止實驗?

在討論和定義好所有內容之後,就可以進行實驗。根據試驗結果,可能需要定義(RSD)度量。除了幫你找出應用程序中之前未被發現的問題之外,混沌工程也會顯著提高你對系統的信心——這是一種很好的感覺。

總結

總的來說,在今天的分佈式系統環境中,RSD是一個必選項。雖然學習如何設計和實現彈性模式相對容易,但RSD所面臨的實際挑戰通常不在於編碼方面。

分佈式系統本身的複雜性和分佈式系統的功能設計讓實現可持續的彈性變得更加困難。同時,Ops和Dev之間缺少反饋循環、過於複雜的彈性設計,或者缺乏對RSD業務案例的理解,等等,通常都會帶來阻礙。不過,瞭解挑戰是成功掌握它們的第一步……

參考

  1. “Release It!”第2版,作者Michael T. Nygard,Pragmatic Bookshelf於2018年出版
  2. “Patterns for Fault Tolerant Software”,作者Robert S. Hanmer,Wiley於2007年出版

關於作者

image

Uwe Friedrichsen在IT領域有多年經驗。作爲codecentric(https://codecentric.rs/)的CTO和合夥人,他總是在尋找創新的想法和概念。他目前關注的領域是(分佈式)系統設計、深度學習和未來的IT。通常,你可以在一些分享大會上看到他的身影。他也喜歡寫文章、發推文,等等。

查看英文原文https://www.infoq.com/articles/towards-resilient-software-design

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章