第10章 分層架構(gòu)風(fēng)格

分層架構(gòu)風(fēng)格碌廓,也稱為n層架構(gòu)風(fēng)格,是最常見的架構(gòu)風(fēng)格之一蝙云。這種風(fēng)格的架構(gòu)是大多數(shù)應(yīng)用程序的事實(shí)標(biāo)準(zhǔn)氓皱,主要是因?yàn)樗唵巍⒂押貌⑶页杀镜筒佟8鶕?jù)康威定律波材,使用分層架構(gòu)開發(fā)應(yīng)用程序也是一種非常自然的方式,設(shè)計(jì)系統(tǒng)的組織最終會產(chǎn)生與組織架構(gòu)相同的設(shè)計(jì)身隐。在大多數(shù)組織中廷区,都有用戶界面(UI)開發(fā)人員、后端開發(fā)人員贾铝、規(guī)則開發(fā)人員和數(shù)據(jù)庫專家(DBA)這些角色隙轻。這些組織層很好地適應(yīng)了傳統(tǒng)分層架構(gòu)的各個層,使其成為許多業(yè)務(wù)應(yīng)用程序的自然選擇垢揩。分層架構(gòu)風(fēng)格也分為幾種架構(gòu)反模式玖绿,包括隱含架構(gòu)反模式和偶然架構(gòu)反模式。如果一個開發(fā)人員或架構(gòu)師不確定他們正在使用哪種架構(gòu)風(fēng)格叁巨,或者一個敏捷開發(fā)團(tuán)隊(duì)“剛開始編碼”斑匪,那么很有可能他們正在采用分層架構(gòu)風(fēng)格。

拓?fù)浣Y(jié)構(gòu)

組件在分層架構(gòu)中被組織成邏輯水平層锋勺,每個層在應(yīng)用中執(zhí)行特定的角色(例如表示邏輯或業(yè)務(wù)邏輯)蚀瘸。盡管對于必須存在的層的數(shù)量和類型沒有特定的限制,但是大多數(shù)分層體系結(jié)構(gòu)由四個標(biāo)準(zhǔn)層組成:表示層庶橱、業(yè)務(wù)層贮勃、持久層和數(shù)據(jù)庫層,如圖10-1所示苏章。在某些情況下寂嘉,業(yè)務(wù)層和持久性層被組合成一個業(yè)務(wù)層,特別是當(dāng)持久性邏輯(如SQL或HSQL)嵌入到業(yè)務(wù)層組件中時。因此垫释,較小的應(yīng)用可能只有三層丝格,而更大和更復(fù)雜的業(yè)務(wù)應(yīng)用可能包含五層或更多。

圖10-1. 分層架構(gòu)風(fēng)格中的標(biāo)準(zhǔn)邏輯層

圖10-2從物理分層(部署)的角度說明了各種拓?fù)浣Y(jié)構(gòu)變體棵譬。第一個變體將表示層显蝌、業(yè)務(wù)層和持久層組合到一個部署單元中,數(shù)據(jù)庫層通常表示為一個單獨(dú)的外部物理數(shù)據(jù)庫(或文件系統(tǒng))订咸。第二個變體在物理上將表示層劃分為單獨(dú)的部署單元曼尊,業(yè)務(wù)層和持久層合并為第二個部署單元。同樣脏嚷,使用此變體骆撇,數(shù)據(jù)庫層在物理上通常通過外部數(shù)據(jù)庫或文件系統(tǒng)進(jìn)行分離。第三個變體將所有四個標(biāo)準(zhǔn)層組合到一個部署中父叙,包括數(shù)據(jù)庫層神郊。對于具有內(nèi)部嵌入式數(shù)據(jù)庫或內(nèi)存數(shù)據(jù)庫的較小應(yīng)用程序,此變體可能很有用趾唱。許多內(nèi)部(“免費(fèi)”)產(chǎn)品都是使用第三種變體建設(shè)并交付給客戶的涌乳。

圖10-2. 物理拓?fù)洌ú渴穑┳凅w??

分層架構(gòu)風(fēng)格的每一層在架構(gòu)中都有特定的角色和責(zé)任。例如甜癞,表示層將負(fù)責(zé)處理所有用戶界面和瀏覽器通信邏輯夕晓,而業(yè)務(wù)層將負(fù)責(zé)執(zhí)行與請求相關(guān)聯(lián)的特定業(yè)務(wù)規(guī)則。架構(gòu)中的每一層圍繞滿足特定業(yè)務(wù)請求所需完成的工作形成一個抽象悠咱。例如蒸辆,表示層不需要知道或擔(dān)心如何獲取客戶數(shù)據(jù);它只需要在屏幕上以特定格式顯示這些信息析既。同樣躬贡,業(yè)務(wù)層也不需要關(guān)心如何格式化客戶數(shù)據(jù)以便在屏幕上顯示,甚至不需要知道客戶數(shù)據(jù)來自何處眼坏;業(yè)務(wù)層只需要從持久層獲取數(shù)據(jù)逗宜,對數(shù)據(jù)執(zhí)行業(yè)務(wù)邏輯(例如計(jì)算值或聚合數(shù)據(jù)),并將這些信息傳遞到表示層空骚。分層架構(gòu)風(fēng)格中的關(guān)注概念分離使得在架構(gòu)中構(gòu)建有效的角色和責(zé)任模型變得容易。例如擂仍,表示層中的組件只處理顯示邏輯囤屹,而駐留在業(yè)務(wù)層中的組件只處理業(yè)務(wù)邏輯。這使得開發(fā)人員能夠利用他們特定的技術(shù)專長來專注于特定領(lǐng)域的技術(shù)方面的內(nèi)容(例如表示邏輯或持久性邏輯)逢渔。然而肋坚,這種好處的代價(jià)是缺乏整體靈活性(快速響應(yīng)變化的能力)。

分層架構(gòu)是從技術(shù)上劃分的架構(gòu)(與領(lǐng)域劃分的架構(gòu)相反)。組件分組不是按領(lǐng)域(如客戶)分組智厌,而是按它們在架構(gòu)中的技術(shù)角色(如表示層或業(yè)務(wù)層)分組诲泌。這導(dǎo)致任何特定的業(yè)務(wù)領(lǐng)域都會分布在架構(gòu)的所有層中。例如铣鹏,“客戶”領(lǐng)域邏輯包含在表示層敷扫、業(yè)務(wù)層、規(guī)則層诚卸、服務(wù)層和數(shù)據(jù)庫層中葵第,因此很難更改該領(lǐng)域的邏輯。因此合溺,領(lǐng)域驅(qū)動設(shè)計(jì)方法不太適用于使用分層架構(gòu)風(fēng)格卒密。

隔離層

分層架構(gòu)風(fēng)格中的每個層可以是封閉的,也可以是開放的棠赛。封閉層意味著當(dāng)一個請求自上而下地從一個層移動到另一個層時哮奇,請求不能跳過任何層,而是必須通過它下面的層到達(dá)下一層(如圖10-3)睛约。例如鼎俘,在一個封閉的分層架構(gòu)中,來自表示層的請求必須首先經(jīng)過業(yè)務(wù)層痰腮,然后到達(dá)持久層而芥,最后才能到達(dá)數(shù)據(jù)庫層。

圖10-3. 分層架構(gòu)中的封閉層??

在圖10-3中膀值,表示層繞過任何不必要的層(在21世紀(jì)初被稱為快速通道閱讀器模式)直接訪問數(shù)據(jù)庫以進(jìn)行簡單的檢索請求會更快棍丐、更容易。要做到這一點(diǎn)沧踏,業(yè)務(wù)層和持久層必須是開放的歌逢,允許請求繞過其他層。開放層和封閉層哪個更好翘狱?這個問題的答案在于一個被稱為隔離層的關(guān)鍵概念秘案。

隔離層概念意味著在架構(gòu)的一個層中所做的更改通常不會影響其他層中的組件,只要這些層之間的契約保持不變潦匈。每一層都獨(dú)立于其他層阱高,因此對架構(gòu)中其他層的內(nèi)部工作原理知之甚少或一無所知。但是茬缩,為了支持隔離層赤惊,與請求的流動主干相關(guān)的層必須是封閉的。如果表示層可以直接訪問持久層凰锡,那么對持久層所做的更改將同時影響業(yè)務(wù)層和表示層未舟,從而產(chǎn)生一個耦合非常緊密的應(yīng)用圈暗,組件之間具有層間的相互依賴關(guān)系。這種類型的架構(gòu)會變得非常脆弱裕膀,變更會非常困難而且成本高昂员串。

隔離層概念還允許在不影響任何其他層的情況下替換架構(gòu)中的任何層(同樣,假設(shè)定義良好的契約和使用業(yè)務(wù)委托模式)昼扛。例如寸齐,您可以利用分層架構(gòu)風(fēng)格中的隔離層概念,在不會影響應(yīng)用中的任何其他層的情況下將舊的JavaServer Faces(JSF)表示層替換為React.js野揪。

添加層

雖然封閉層有助于隔離層访忿,因此有助于隔離架構(gòu)中的更改,但有時某些層開放是有意義的斯稳。例如海铆,假設(shè)業(yè)務(wù)層中有共享對象,這些對象包含業(yè)務(wù)組件的公共功能(例如日期和字符串實(shí)用程序類挣惰、審計(jì)類卧斟、日志類等等)。假設(shè)有一個架構(gòu)決策憎茂,表示層不能使用這些共享業(yè)務(wù)對象珍语。這個約束如圖10-4所示,虛線從表示層組件到業(yè)務(wù)層中的共享業(yè)務(wù)對象竖幔。這個場景很難管理和控制板乙,因?yàn)樵诩軜?gòu)上,表示層可以訪問業(yè)務(wù)層拳氢,因此可以訪問該層中的共享對象募逞。

圖10-4. 業(yè)務(wù)層中的共享對象

從架構(gòu)上強(qiáng)制執(zhí)行此限制的一種方法是向架構(gòu)添加一個包含所有共享業(yè)務(wù)對象的新服務(wù)層。現(xiàn)在添加這個新的層從架構(gòu)上限制表示層訪問共享業(yè)務(wù)對象馋评,因?yàn)闃I(yè)務(wù)層是封閉的(見圖10-5)放接。但是,新的服務(wù)層必須標(biāo)記為“開放”留特;否則業(yè)務(wù)層將被迫通過服務(wù)層來訪問持久層纠脾。將服務(wù)層標(biāo)記為“開放”允許業(yè)務(wù)層訪問該層(如實(shí)心箭頭所示),或者繞過該層并向下轉(zhuǎn)到下一層(如圖10-5中的虛線箭頭所示)蜕青。

圖10-5. 向架構(gòu)添加新的服務(wù)層??

利用開放層和封閉層的概念有助于定義架構(gòu)層次和請求流之間的關(guān)系苟蹈。它還為開發(fā)人員提供了了解架構(gòu)中的各種層的訪問限制的必要信息和指導(dǎo)。如果不能記錄或正確地傳達(dá)架構(gòu)中的哪些層是開放的和封閉的(以及為什么)右核,通常會導(dǎo)致緊密耦合和脆弱的架構(gòu)汉操,這些架構(gòu)將很難測試、維護(hù)和部署蒙兰。

其他考慮事項(xiàng)

當(dāng)還不知道最終將使用哪種架構(gòu)風(fēng)格時磷瘤,分層架構(gòu)可以作為大多數(shù)應(yīng)用的一個良好的起點(diǎn)。在許多微服務(wù)工作的普遍實(shí)踐中搜变,當(dāng)架構(gòu)師仍在確定微服務(wù)是否是正確的架構(gòu)選擇時采缚,但開發(fā)必須開始。然而挠他,當(dāng)使用這種技術(shù)時扳抽,一定要將重用保持在最低限度,并使對象層次結(jié)構(gòu)(繼承樹的深度)做夠的淺殖侵,以便保持良好的模塊化水平贸呢。這將有助于以后轉(zhuǎn)向另一種架構(gòu)風(fēng)格。

對于分層架構(gòu)拢军,需要注意的一點(diǎn)是不要陷入污水池反模式楞陷。當(dāng)請求以簡單的傳遞處理方式從一層移動到另一層,而每個層中并沒有執(zhí)行業(yè)務(wù)邏輯時茉唉,就會出現(xiàn)這種反模式固蛾。例如,假設(shè)表示層響應(yīng)用戶的一個簡單請求度陆,以檢索基本的客戶數(shù)據(jù)(例如名稱和地址)艾凯。表示層將請求傳遞給業(yè)務(wù)層,業(yè)務(wù)層只將請求傳遞給規(guī)則層懂傀,而規(guī)則層只將請求傳遞給持久層趾诗,后者對數(shù)據(jù)庫層進(jìn)行簡單的SQL調(diào)用以檢索客戶數(shù)據(jù)。然后蹬蚁,數(shù)據(jù)將一直回傳上去恃泪,而不需要額外的處理或邏輯來聚合、計(jì)算缚忧、應(yīng)用規(guī)則或轉(zhuǎn)換數(shù)據(jù)悟泵。這會導(dǎo)致不必要的對象實(shí)例化和處理,從而影響內(nèi)存消耗和性能闪水。

每一個分層架構(gòu)都至少有一些場景陷入架構(gòu)污水池反模式糕非。確定是否陷入架構(gòu)污水池反模式的關(guān)鍵是分析屬于這一類的請求的百分比。80-20規(guī)則通城蛴埽可以作為很好的判斷實(shí)踐朽肥。例如,如果只有20%的請求是污水池持钉,則可以接受衡招。但是,如果80%的請求都是污水池每强,那么對于問題域來說分層架構(gòu)并不是合適的架構(gòu)風(fēng)格始腾。另一種解決架構(gòu)污水池反模式的方法是讓架構(gòu)中的所有層都開放州刽,當(dāng)然,也要意識到浪箭,代價(jià)是在架構(gòu)中管理變更的難度會增加穗椅。

為什么使用分層架構(gòu)風(fēng)格

分層架構(gòu)風(fēng)格是小型、簡單的應(yīng)用程序或網(wǎng)站的好選擇奶栖。

對于預(yù)算和時間限制非常緊張的情況匹表,分層架構(gòu)也是一個很好的架構(gòu)選擇,尤其是在開始階段宣鄙。由于架構(gòu)簡單性和開發(fā)人員和架構(gòu)師之間對這種架構(gòu)的熟悉度袍镀,分層架構(gòu)可能是成本最低的架構(gòu)風(fēng)格之一,有助于小型應(yīng)用的開發(fā)冻晤。當(dāng)架構(gòu)師仍在分析業(yè)務(wù)需求并且不確定哪種架構(gòu)風(fēng)格是最合適的時候苇羡,分層架構(gòu)風(fēng)格也是一個不錯的選擇。

隨著使用分層架構(gòu)風(fēng)格的應(yīng)用程序的不斷迭代明也,諸如可維護(hù)性宣虾、敏捷性、可測試性和可部署性等特性將受到不利影響温数。因此绣硝,使用分層架構(gòu)的大型應(yīng)用和系統(tǒng)可能更適合使用其他更模塊化的架構(gòu)風(fēng)格。

架構(gòu)特性評級

特性評級表中的一星級評級(如圖10-6所示)意味著特定的架構(gòu)特性在某種架構(gòu)中沒有得到很好的支持撑刺,而五星評級意味著架構(gòu)特性是某種架構(gòu)風(fēng)格中最強(qiáng)大的特性之一鹉胖。記分卡中確定的每個特性的定義見第4章。

圖10-6. 分層架構(gòu)特性評級??

成本低廉和簡單性是分層架構(gòu)風(fēng)格的主要優(yōu)勢够傍。分層架構(gòu)本質(zhì)上是一個單體甫菠,它不具有與分布式架構(gòu)風(fēng)格相關(guān)的復(fù)雜性,它簡單易懂并且構(gòu)建和維護(hù)的成本相對較低冕屯。然而寂诱,值得注意的是,隨著整體分層架構(gòu)變得越來越大安聘,從而變得越來越復(fù)雜痰洒,這些評級開始迅速降低。

這種架構(gòu)風(fēng)格的可部署性和可測試性都非常低浴韭∏鹩鳎可部署性評級低是由于部署成本高、風(fēng)險(xiǎn)高和缺乏頻繁部署能力念颈。在分層架構(gòu)中對一個類文件進(jìn)行簡單的三行更改需要重新部署整個部署單元泉粉,原來的改動暗中會引起潛在的數(shù)據(jù)庫更改、配置更改或其他編碼更改。此外嗡靡,這簡單的三行更改通常會引起其他幾十處的更改跺撼,因此會增加部署的風(fēng)險(xiǎn)(也會增加部署的頻率)。低可測試性評級也反映了這種情況叽躯;通過簡單的三行更改财边,大多數(shù)開發(fā)人員不會花費(fèi)數(shù)小時來執(zhí)行整個回歸測試套件(即使測試套件一開始就存在),尤其是在同一時間對單體應(yīng)用還有其他幾十處更改的情況下点骑。我們給可測試性一個雙星評級(而不是一星),因?yàn)樗軌驅(qū)M件(甚至整個層)使用mock或者stub模擬測試谍夭,這簡化了整個測試工作黑滴。

在這種架構(gòu)風(fēng)格中,總體可靠性為中等(三星級)紧索,主要是由于沒有在大多數(shù)分布式架構(gòu)中存在的網(wǎng)絡(luò)流量袁辈、帶寬和延遲問題。由于單體應(yīng)用部署的本質(zhì)珠漂,再加上可測試性(測試的完整性)和部署風(fēng)險(xiǎn)的低評級晚缩,我們只對分層架構(gòu)的可靠性給出了三星級的評級。

分層架構(gòu)的彈性和可擴(kuò)展性非常低(一星)媳危,主要是由于單體部署和缺乏架構(gòu)模塊化能力荞彼。雖然在一個單體應(yīng)用內(nèi)實(shí)現(xiàn)某些功能的擴(kuò)展是可能的,但這種工作通常需要非常復(fù)雜的設(shè)計(jì)技術(shù)待笑,如多線程鸣皂、內(nèi)部消息傳遞和其他在這種架構(gòu)中不適合使用的并行處理實(shí)踐和技術(shù)。然而暮蹂,由于用戶界面寞缝、后端處理和數(shù)據(jù)庫的單一性,分層架構(gòu)始終是一個單一的系統(tǒng)量子仰泻,因此應(yīng)用只能在單個量子的基礎(chǔ)上擴(kuò)展到一定的程度荆陆。

性能一直是分層架構(gòu)的一個有趣的特性。我們只給了它兩顆星評級集侯,這種架構(gòu)風(fēng)格因?yàn)槿狈Σ⑿刑幚肀惶洹⒎忾]分層和架構(gòu)污水池反模式的原因根本不適合于高性能系統(tǒng)。與可擴(kuò)展性一樣浅悉,性能也可以通過緩存趟据、多線程等來解決,但這并不是這種架構(gòu)風(fēng)格的自然特征术健;架構(gòu)師和開發(fā)人員必須通過大量的工作才能實(shí)現(xiàn)這一切汹碱。

由于單體部署和缺乏架構(gòu)模塊性,分層架構(gòu)不支持容錯荞估。如果分層架構(gòu)的一小部分發(fā)生內(nèi)存不足問題咳促,則整個應(yīng)用單元將受到影響并崩潰稚新。此外,由于大多數(shù)單體應(yīng)用普遍存在較高的平均恢復(fù)時間(MTTR)跪腹,總體可用性受到影響褂删,啟動時間從小型應(yīng)用的2分鐘,到大多數(shù)大型應(yīng)用的15分鐘或更長冲茸。


原文參考:http://www.reibang.com/p/1241f19905f9

全書翻譯目錄:http://www.reibang.com/p/05711d172dfa

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末屯阀,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子轴术,更是在濱河造成了極大的恐慌难衰,老刑警劉巖,帶你破解...
    沈念sama閱讀 216,651評論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件逗栽,死亡現(xiàn)場離奇詭異盖袭,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)彼宠,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,468評論 3 392
  • 文/潘曉璐 我一進(jìn)店門鳄虱,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人凭峡,你說我怎么就攤上這事拙已。” “怎么了想罕?”我有些...
    開封第一講書人閱讀 162,931評論 0 353
  • 文/不壞的土叔 我叫張陵悠栓,是天一觀的道長。 經(jīng)常有香客問我按价,道長惭适,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,218評論 1 292
  • 正文 為了忘掉前任楼镐,我火速辦了婚禮癞志,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘框产。我一直安慰自己凄杯,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,234評論 6 388
  • 文/花漫 我一把揭開白布秉宿。 她就那樣靜靜地躺著戒突,像睡著了一般。 火紅的嫁衣襯著肌膚如雪描睦。 梳的紋絲不亂的頭發(fā)上膊存,一...
    開封第一講書人閱讀 51,198評論 1 299
  • 那天,我揣著相機(jī)與錄音,去河邊找鬼隔崎。 笑死今艺,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的爵卒。 我是一名探鬼主播虚缎,決...
    沈念sama閱讀 40,084評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼钓株!你這毒婦竟也來了实牡?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 38,926評論 0 274
  • 序言:老撾萬榮一對情侶失蹤轴合,失蹤者是張志新(化名)和其女友劉穎铲掐,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體值桩,經(jīng)...
    沈念sama閱讀 45,341評論 1 311
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,563評論 2 333
  • 正文 我和宋清朗相戀三年豪椿,在試婚紗的時候發(fā)現(xiàn)自己被綠了奔坟。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,731評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡搭盾,死狀恐怖咳秉,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情鸯隅,我是刑警寧澤澜建,帶...
    沈念sama閱讀 35,430評論 5 343
  • 正文 年R本政府宣布,位于F島的核電站蝌以,受9級特大地震影響炕舵,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜跟畅,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,036評論 3 326
  • 文/蒙蒙 一咽筋、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧徊件,春花似錦奸攻、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,676評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至部翘,卻和暖如春硝训,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,829評論 1 269
  • 我被黑心中介騙來泰國打工捎迫, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留晃酒,地道東北人。 一個月前我還...
    沈念sama閱讀 47,743評論 2 368
  • 正文 我出身青樓窄绒,卻偏偏與公主長得像贝次,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子彰导,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,629評論 2 354

推薦閱讀更多精彩內(nèi)容