官术网_书友最值得收藏!

1.2 單體系統(tǒng)時代

單體架構(gòu)是今天絕大多數(shù)軟件開發(fā)者都學(xué)習(xí)、實踐過的一種軟件架構(gòu),許多介紹微服務(wù)的圖書和技術(shù)資料中也常把這種架構(gòu)風(fēng)格的應(yīng)用稱作“巨石系統(tǒng)”(Monolithic Application)?!皢误w架構(gòu)”在整個軟件架構(gòu)演進(jìn)的歷史進(jìn)程里,是出現(xiàn)時間最早、應(yīng)用范圍最廣、使用人數(shù)最多、統(tǒng)治歷史最長的一種架構(gòu)風(fēng)格,但“單體”這個名稱,卻是在微服務(wù)開始流行之后才“事后追認(rèn)”所形成的概念。此前,并沒有多少人將“單體”看作一種架構(gòu),如果你去查找軟件架構(gòu)的開發(fā)資料,可以輕易地找出大量以微服務(wù)為主題的圖書和文章,卻很難找出專門教你如何開發(fā)單體架構(gòu)的任何形式的材料,這一方面體現(xiàn)了單體架構(gòu)本身的簡單性,另一方面也體現(xiàn)出在相當(dāng)長的時間里,大家都已經(jīng)習(xí)慣了軟件架構(gòu)就應(yīng)該是單體這種樣子。

剖析單體架構(gòu)之前,我們有必要先厘清一個概念誤區(qū),在許多微服務(wù)的資料里,單體系統(tǒng)往往是以“反派角色”的身份登場的,譬如著名的微服務(wù)入門書《微服務(wù)架構(gòu)設(shè)計模式》,第1章的名字就是“逃離單體的地獄”。這些材料所講的單體系統(tǒng),其實都有一個隱含定語:“大型的單體系統(tǒng)”。對于小型系統(tǒng),單臺機器就足以支撐其良好運行的系統(tǒng),不僅易于開發(fā)、測試、部署,且由于系統(tǒng)中各個功能、模塊、方法的調(diào)用過程都是進(jìn)程內(nèi)調(diào)用,不會發(fā)生進(jìn)程間通信(Inter-Process Communication,IPC[1]),因此連運行效率也是最高的,所以此時的單體架構(gòu)完全不應(yīng)該被貼上“反派角色”的標(biāo)簽,反倒是那些愛趕技術(shù)潮流卻不顧需求現(xiàn)狀的微服務(wù)吹捧者更像是個反派。單體系統(tǒng)的不足,必須在軟件的性能需求超過了單機、軟件的開發(fā)人員規(guī)模明顯超過了“2 Pizza Team”[2]范疇的前提下才有討論的價值,因此,本書后續(xù)討論中所說的單體,均特指“大型的單體系統(tǒng)”。也正是因此,本節(jié)中說到“單體是出現(xiàn)最早的架構(gòu)風(fēng)格”,與上一節(jié)開篇提到的“使用多個獨立的分布式服務(wù)共同構(gòu)建一個更大型系統(tǒng)的設(shè)想與實際嘗試,反而要比今天大家所了解的大型單體系統(tǒng)出現(xiàn)的時間更早”實際并無矛盾。

額外知識

Monolith means composed all in one piece.The Monolithic application describes a single-tiered software application in which different components combined into a single program from a single platform.

單體意味著自包含。單體應(yīng)用描述了一種由同一技術(shù)平臺的不同組件構(gòu)成的單層軟件。

——Wikipedia

盡管“Monolithic”這個詞語本身的意思,“巨石”,確實帶有一些“不可拆分”的隱含意味,但人們也不應(yīng)該簡單粗暴地把單體系統(tǒng)在維基百科上的定義“all in one piece”翻譯成“鐵板一塊”,它其實更接近于“自給自足”(Self-Contained,在計算機中譯為“自包含”)的含義。不過,這種“鐵板一塊”的譯法不能全算作段子,筆者相信肯定有一部分人說起單體架構(gòu)、巨石系統(tǒng)時,在腦海中閃過的第一個缺點就是它的不可拆分、難以擴展,因此才不能支撐越來越大的軟件規(guī)模。這種想法看似合理,其實是有失偏頗的,至少不完整。

從縱向角度來看,筆者在實際生產(chǎn)環(huán)境里從未見過哪個大型現(xiàn)代信息系統(tǒng)是完全不分層的。分層架構(gòu)(Layered Architecture)已是現(xiàn)在所有信息系統(tǒng)建設(shè)中普遍認(rèn)可、采用的軟件設(shè)計方法,無論是單體還是微服務(wù),抑或是其他架構(gòu)風(fēng)格,都會對代碼進(jìn)行縱向?qū)哟蝿澐?,收到的外部請求在各層之間以不同形式的數(shù)據(jù)結(jié)構(gòu)進(jìn)行流轉(zhuǎn)傳遞,觸及最末端的數(shù)據(jù)庫后按相反的順序回饋響應(yīng),如圖1-1所示。對于這個意義上的“可拆分”,單體架構(gòu)完全不會展露出絲毫的弱勢,反而可能會因更容易開發(fā)、部署、測試而獲得更好的便捷性。

從橫向角度來看,單體架構(gòu)也支持按照技術(shù)、功能、職責(zé)等維度,將軟件拆分為各種模塊,以便重用和管理代碼。單體系統(tǒng)并不意味著只能有一個整體的程序封裝形式,如果需要,它完全可以由多個JAR、WAR、DLL、Assembly或者其他模塊格式來構(gòu)成。即使是從橫向擴展(Scale Horizontally)的角度來衡量,在負(fù)載均衡器之后同時部署若干個相同的單體系統(tǒng)副本,以達(dá)到分?jǐn)偭髁繅毫Φ男Ч彩欠浅3R姷男枨蟆?/p>

在“拆分”這方面,單體系統(tǒng)的真正缺陷不在如何拆分,而在拆分之后的自治與隔離能力上。由于所有代碼都運行在同一個進(jìn)程內(nèi),所有模塊、方法的調(diào)用都無須考慮網(wǎng)絡(luò)分區(qū)、對象復(fù)制這些麻煩的事和性能損失,但在獲得進(jìn)程內(nèi)調(diào)用的簡單、高效等好處的同時,也意味著如果任何一部分代碼出現(xiàn)缺陷,過度消耗了進(jìn)程空間內(nèi)的資源,所造成的影響也是全局性的、難以隔離的。譬如內(nèi)存泄漏、線程爆炸、阻塞、死循環(huán)等問題,都將會影響整個程序,而不僅僅是影響某一個功能、模塊本身的正常運作。如果出現(xiàn)問題的是某些更高層次的公共資源,譬如端口號或者數(shù)據(jù)庫連接池泄漏,還將會影響整臺機器甚至集群中其他單體副本的正常工作。

圖1-1 分層架構(gòu)示意

同樣,由于所有代碼都共享同一個進(jìn)程,不能隔離,也就無法(其實還是有辦法的,譬如使用OSGi這種運行時模塊化框架,但是很別扭、很復(fù)雜)做到單獨停止、更新、升級某一部分代碼,因為不可能有“停掉半個進(jìn)程,重啟1/4個程序”這樣不合邏輯的操作,所以從可維護(hù)性來說,單體系統(tǒng)也是不占優(yōu)勢的。對于單體系統(tǒng),在對程序升級、修改時往往需要制定專門的停機更新計劃,做灰度發(fā)布、A/B測試也相對更復(fù)雜。

如果說共享同一進(jìn)程獲得簡單、高效的代價是同時損失了各個功能模塊的自治與隔離能力,那這兩者孰輕孰重呢?這個問題的潛臺詞似乎是在比較微服務(wù)、單體架構(gòu)哪種更好用、更優(yōu)秀。筆者認(rèn)為“好用和優(yōu)秀”不會是放之四海皆準(zhǔn)的,這點不妨舉一個淺顯的例子加以說明。譬如,沃爾瑪將超市分為倉儲部、采購部、安保部、庫存管理部、巡檢部、質(zhì)量管理部、市場營銷部等,劃清職責(zé),明確邊界,讓管理能力能支持企業(yè)的成長規(guī)模。但如果是你家樓下開的小賣部,爸、媽加兒子,再算上看家的中華田園犬小黃一共也就只有四名員工,再去追求“先進(jìn)管理”,劃分倉儲部、采購部、庫存管理部……那純粹是給自己找麻煩。單體架構(gòu)下,哪怕是信息系統(tǒng)中兩個相互毫無關(guān)聯(lián)的子系統(tǒng),也依然會部署在同一個進(jìn)程中。當(dāng)系統(tǒng)規(guī)模小的時候,這是優(yōu)勢,但當(dāng)系統(tǒng)規(guī)模大或程序需要修改的時候,其部署的成本、技術(shù)升級的遷移成本都會變得非常昂貴。繼續(xù)以前面的例子來比喻,當(dāng)公司小時,讓安保部和質(zhì)檢部這兩個不相干的部門在同一棟大樓中辦公是節(jié)約資源;但當(dāng)公司人數(shù)增加,辦公室已經(jīng)擁擠不堪時,最多只能在樓頂加蓋新樓層(相當(dāng)于增強硬件性能)來解決辦公問題,而不能讓安保部和質(zhì)檢部分開地方辦公,這便是缺陷所在。

由于隔離能力的缺失,單體除了難以阻斷錯誤傳播、不便于動態(tài)更新程序以外,還面臨難以技術(shù)異構(gòu)的困難,每個模塊的代碼通常都需要使用一樣的程序語言,乃至一樣的編程框架去開發(fā)。單體系統(tǒng)的技術(shù)棧異構(gòu)并非一定做不到,譬如JNI就可以讓Java混用C或C++實現(xiàn),但這通常是迫不得已的,并不是優(yōu)雅的選擇。

不過,以上列舉的這些問題都還不是今天以微服務(wù)取代單體系統(tǒng)成為潮流趨勢的根本原因,筆者認(rèn)為最重要的原因是:單體系統(tǒng)很難兼容“Phoenix”的特性。這種架構(gòu)風(fēng)格潛在的要求是希望系統(tǒng)的每一個部件、每一處代碼都盡量可靠,盡量不出或少出缺陷。然而戰(zhàn)術(shù)層面再優(yōu)秀,也很難彌補戰(zhàn)略層面的不足。單體系統(tǒng)靠高質(zhì)量來保證高可靠性的思路,在小規(guī)模軟件上還能運作良好,但當(dāng)系統(tǒng)規(guī)模越來越大時,交付一個可靠的單體系統(tǒng)就變得越來越具有挑戰(zhàn)性。如本書前言所說,正是隨著軟件架構(gòu)演進(jìn),構(gòu)建可靠系統(tǒng)的觀念從“追求盡量不出錯”到正視“出錯是必然”的轉(zhuǎn)變,才是微服務(wù)架構(gòu)得以挑戰(zhàn)并逐步取代單體架構(gòu)的底氣所在。

為了允許程序出錯,獲得自治與隔離的能力,以及實現(xiàn)可以技術(shù)異構(gòu)等目標(biāo),是繼性能與算力之后,讓程序再次選擇分布式的理由。然而,開發(fā)分布式程序也并不意味著一定要依靠今天的微服務(wù)架構(gòu)才能實現(xiàn)。在新舊世紀(jì)之交,人們曾經(jīng)探索過幾種服務(wù)拆分方法,將一個大的單體系統(tǒng)拆分為若干個更小的、不運行在同一個進(jìn)程的獨立服務(wù),這些服務(wù)拆分方法后來帶來了面向服務(wù)架構(gòu)(Service-Oriented Architecture)的一段興盛期,我們稱其為“SOA時代”。

[1] 廣義上講,可以認(rèn)為RPC是IPC的一種特例,但請注意這兩個詞里的“PC”不是同個單詞的縮寫。

[2] 由亞馬遜創(chuàng)始人Jeff Bezos提出的衡量團(tuán)隊大小的“量詞”。指兩個Pizza能喂飽的人數(shù),大概是6~12人。

主站蜘蛛池模板: 西充县| 孟津县| 库伦旗| 郁南县| 中卫市| 外汇| 报价| 吉木乃县| 新津县| 南华县| 麻栗坡县| 巩留县| 盘锦市| 南乐县| 盘锦市| 年辖:市辖区| 华坪县| 永新县| 神池县| 盐亭县| 漳平市| 南安市| 白朗县| 天全县| 沛县| 宜君县| 新沂市| 神农架林区| 巴彦县| 龙山县| 齐齐哈尔市| 浪卡子县| 巴林右旗| 金塔县| 孟村| 泰兴市| 安乡县| 陆良县| 潍坊市| 云阳县| 芦山县|