- 鳳凰架構:構建可靠的大型分布式系統
- 周志明
- 3184字
- 2021-06-24 11:30:48
自序
流水不腐,戶樞不蠹
“Phoenix”(鳳凰)這個詞在東方的技術書中不常用,但在西方的軟件工程讀物中,尤其是在關于敏捷、DevOps話題的作品中時常出現。軟件工程小說《鳳凰項目》(見圖1)講述了徘徊在死亡邊緣的鳳凰項目在精益方法下浴火重生的故事;Martin Fowler在詮釋“持續交付”時,曾多次提到“Phoenix Server”(鳳凰服務器,取其能夠“涅槃重生”之意)與“Snowflake Server”(雪花服務器,取其“世界上沒有相同的兩片雪花”之意)的優劣比對。也許是東西方文化的差異,盡管有“失敗是成功之母”這樣的諺語,但我們東方人的骨子里更注重的還是一次把事做對、做好,盡量別出亂子;而西方人則要“更看得開”一些,把出錯看作正常甚至是必需的發展過程,只要出了問題能夠兜底使其重回正軌便好。

圖1 《鳳凰項目》
在軟件工程里,任何產品的研發,如果持續時間很長,人總免不了疏忽、犯錯,導致代碼存在缺陷,電腦宕機崩潰,網絡堵塞中斷……如果一項工程需要大量的人員共同研發某個大規模的軟件產品,并使其分布在網絡中的大量的服務器節點中同時運行,隨著項目規模增大、運作時間變長,其必然會受到墨菲定律的無情打擊。
為了得到高質量的軟件產品,我們是應該把精力更多地集中在提升其中每一個人員、過程、產出物的能力和質量上?還是應該把更多精力放在整體流程和架構上?
筆者對這個問題先給一個“和稀泥”式的回答:這兩者都重要。前者重術,后者重道;前者更多與編碼能力相關,后者更多與軟件架構相關;前者主要由開發者個體的水平決定,后者主要由技術決策者的水平決定。
然而,筆者也必須強調此問題的另外一面:這兩者的理解路徑和抽象程度是不一樣的。如何學習一項具體的語言、框架、工具,譬如Java、Spring、Vue.js等,是相對具象的,不論其蘊含的內容多少,復雜程度高低,它至少是能看得見、摸得著的。而如何學習某一種風格的架構方法,譬如單體、微服務、服務網格、無服務、云原生等,則是相對抽象的,談論它們可能要面臨“一千個人眼中有一千個哈姆雷特”的困境。談這方面的話題,若要言之有物,就不能是單純的經驗陳述。回到這些架構根本的出發點和問題上,筆者認為,真正去使用這些不同風格的架構方法來實現某些需求,解決某些問題,然后在實踐中觀察它們的異同優劣,會是一種很好的也許是最好的講述方式。筆者想說一下這些架構,而且想說得透徹明白,就需要代碼與文字的配合,于是便有了這本書,以及與它配套的實踐項目。
可靠的系統
讓我們再來思考一個問題,構建一個大規模但依然可靠的軟件系統,是否可行?
這個問題聽起來的第一感覺也許會有點荒謬。如果這個事情從理論上來說就是根本不可能的,那我們這些軟件開發人員在瞎忙活些什么?但你再仔細想想,前面才提到的“墨菲定律”和在“大規模”這個前提下必然會遇到各種“不靠譜”的人員、代碼、硬件、網絡等因素,從中能得出一個聽起來頗為合理的推論:如果一項工作要經過多個“不靠譜”的過程相互協作完成,其中的誤差應會不斷累積疊加,導致最終結果必然不能收斂穩定。
這個問題也并非杞人憂天、庸人自擾式的瞎操心,計算機之父馮·諾依曼在20世紀40年代末期,曾經花費大約兩年時間,研究這個問題并且得出了一個理論——自復制自動機(Self-Reproducing Automata)(見圖2)。這個理論以機器應該如何從基本的部件中構造出與自身相同的另一臺機器引出,其目的并不是想單純地模擬或者理解生物體的自我復制,也并不是想簡單地制造自我復制的計算機,而是想回答一個理論問題:如何用一些“不可靠”部件構造出一個可靠的系統。

圖2 當時自復制自動機的藝術表示(圖片來自維基百科)
自復制自動機恰好就是一個最好的用“不可靠”部件構造可靠系統的例子。這里,“不可靠”部件可以理解為構成生命的大量細胞,甚至是分子。由于熱力學擾動、生物復制差錯等因素干擾,這些分子本身并不可靠。但是生命系統之所以可靠,恰是因為它可以使用“不可靠”部件來完成遺傳迭代。這其中的關鍵點便是承認細胞等零部件可能會出錯,某個具體的零部件可能會崩潰消亡,但在存續生命的微生態系統中其后代一定會出現,重新代替該零部件,實現它的作用,以維持系統的整體穩定。在這個微生態里,每一個部件都可以看作一只“不死鳥”(Phoenix),它會老邁,又能涅槃重生。
架構的演進
從大型機(Mainframe)、原始分布式(Distributed)、大型單體(Monolithic)、面向服務(Service-Oriented)、微服務(Microservice)、服務網格(Service Mesh)到無服務(Serverless)等,技術架構確實呈現出“從大到小”的發展趨勢。近年來,自微服務興起以后,涌現出各類文章去總結、贊美微服務帶來的種種好處,諸如簡化部署、邏輯拆分更清晰、便于技術異構、易于伸縮拓展以提供更高的性能等,這些當然都是重要優點和動力。可是,如果不拘泥于特定系統或特定某個問題,以更宏觀的角度來看,前面所列的種種好處都只能算是“錦上添花”,是屬于讓系統“活得更好”的動因,肯定比不上系統如何“確保生存”的需求更關鍵、更貼近本質。在筆者看來,架構演變最重要的驅動力,或者說這種“從大到小”的變化趨勢的最根本驅動力,始終都是為了方便某個服務能夠順利地“死去”與“重生”。個體服務的生死更迭,是關系到整個系統能否可靠存續的關鍵因素。
舉個例子,某企業中應用的單體架構的Java系統,其更新、升級都必須要有固定的停機計劃,必須在特定的時間窗口內才能按時開始,且必須按時結束。如果出現了非計劃的宕機,那便是生產事故。但是軟件的缺陷不會遵循定下的停機計劃來“安排時間出錯”。為了應對缺陷與變化,做到不停機地檢修,Java曾經制定了OSGi和JVMTI Instrumentation等復雜的HotSwap方案,以實現“給奔跑中的汽車更換輪胎”這種匪夷所思卻又無可奈何的需求。而在微服務架構的視角下,所謂系統檢修,不過只是一次在線服務更新而已,先停掉1/3的機器,升級新的軟件版本,再有條不紊地導流、測試、做金絲雀發布,一切都顯得如此理所當然、平淡尋常。在無服務架構的視角下,我們甚至都不需要關心服務所運行的基礎設施,連機器是哪臺都不必知道,停機升級就更無須關注了。
流水不腐。有老朽,有消亡,有重生,有更迭,才是生態運行的合理規律。設想一下,如果你的系統中的每個部件都符合“Phoenix”的特性,哪怕其中某些部件采用了由“極不靠譜”的人員所開發的“極不靠譜”的程序,哪怕存在嚴重的內存泄漏問題,哪怕最多只能服務三分鐘就會崩潰,只要在整體架構設計有恰當且自動化的錯誤熔斷、服務淘汰和重建機制,從系統外部來觀察,架構仍然有可能表現出穩定和健壯的服務能力。
鳳凰架構
在企業軟件開發的歷史中,一項新技術發布時,常有伴以該技術開發的“寵物店”(PetStore)作為演示的傳統(如J2EE PetStore、.NET PetShop、Spring PetClinic等)。在對不同架構風格的演示中,筆者本也希望能遵循此傳統,卻無奈從來沒養過寵物,遂改行開了書店(Fenix’s Bookstore),里面出售了幾本筆者的著作,算是夾帶一點私貨,同時也避免了使用素材時的版權隱患。
盡管相信沒有人會誤解,但筆者最后還是多強調一句,Oracle、Microsoft、Pivotal等公司設計“寵物店”的目的絕不是為了日后能在網上販賣“寵物”,而是純粹為了演示技術。所以也請勿以“實現這種學生畢業設計復雜度的需求,引入如此規模的架構或框架,純屬大炮打蒼蠅,肯定是過度設計”的眼光來看待接下來的“Fenix’s Bookstore”項目。相反,如果可能的話,筆者會在有新的技術、框架發布時,持續更新,以恰當的形式添加到項目的不同版本中,其技術棧可能越來越復雜。筆者希望把這些新的、不斷發展的知識,融入已有的知識框架之中,便于自己學習、理解、思考,同時能將這些技術連同自己的觀點和看法分享給更多感興趣的人。
也算是緣分,網名“IcyFenix”是二十多年前筆者從中學時代開始使用的,它源自暴雪公司的即時戰略游戲《星際爭霸》的Protoss英雄Fenix。如名字預示的那樣,他曾經是Zealot,犧牲后以Dragoon的形式重生,帶領Protoss與刀鋒女王Kerrigan繼續抗爭。盡管中學時期我已經篤定自己未來肯定會從事信息技術相關的工作,但顯然不可能預計到二十年后我會寫下這些文字。
所以,既然我們要開始一段關于“Phoenix”的代碼與故事,那便叫它“鳳凰架構”,如何?
- 嵌入式Linux開發技術
- Windows Vista基礎與應用精品教程
- Linux運維實戰:CentOS7.6操作系統從入門到精通
- Implementing Cisco UCS Solutions
- 鴻蒙生態:開啟萬物互聯的智慧新時代
- UNIX操作系統設計
- 精解Windows 8
- 新手易學:系統安裝與重裝
- OpenStack系統架構設計實戰
- ElasticSearch Cookbook
- Windows 7使用詳解(修訂版)
- Hands-On GPU Programming with Python and CUDA
- CSS揭秘
- Responsive Web Design with AngularJS
- Gradle Effective Implementations Guide(Second Edition)