天天看點

針對架構設計的幾個痛點,我總結出的架構原則和模式

分層架構是最常見的架構,也被稱為n層架構。多年以來,許多企業和公司都在他們的項目中使用這種架構,它已經幾乎成為事實标準,是以被大多數架構師、開發者和軟體設計者所熟知。

分層架構中的層次群組件是水準方向的分層,每層扮演應用程式中特定的角色。根據需求和軟體複雜度,我們可以設計n層,但大多數應用程式使用3-4層。有太多層的設計會很糟糕,将導緻複雜度的上升,因為我們必須維護每一層。在傳統的分層架構中,分層包括表現層、業務或者服務層,以及資料通路層。 表現層負責應用程式的使用者互動和使用者體驗(外觀和視覺)。通常我們會使用資料傳輸對象(data transfer object)将資料帶到這一層,然後使用視圖模型(view model)渲染到用戶端。業務層接收請求并執行業務規則。資料通路層負責操作各種類型的資料庫,每個通路資料庫的請求都要經過這一層。

分層架構中的核心概念是管理依賴。如果我們使用依賴倒置原則和測試驅動開發(test driven development),我們的架構會有更好的健壯性。因為,我們要保證所有可能的用例都有測試用例。

我們需要這樣的備援,即使業務層沒有處理業務規則,也要通過業務層來調用資料層,這叫分層隔離。對于某些功能,如果我們從表現層直接通路資料層,那麼資料層後續的任何變動都将影響到業務層和表現層。分層架構中的一個重要的概念就是分層的開閉原則。如果某層是關閉的,那麼每個請求都要經過着一層。相反,如果該層是開放的,那麼請求可以繞過這一層,直接到下一層。

分層隔離有利于降低整個應用程式的複雜度。某些功能并不需要經過每一層,這時我們需要根據開閉原則來簡化實作。

分層架構是solid原則的通用架構,當我們不确定哪種架構更合适的時候,分層架構将是一個很好的起點。我們需要注意防止架構陷入污水池反模式。這種反模式描述了請求經過分層,但沒做任何事或者隻處理了很少的事。如果我們的請求經過所有分層而沒有做任何事,這就是污水池反模式的征兆。如果20%的請求隻是經過各層,而80%的請求實際做事,這還好,如果這個比率不是這樣的,那麼我們已經患上反模式綜合征。此外,分層架構可以演變為巨石應用(monolith),導緻代碼庫難以維護。

分層架構分析:

靈活性:總體靈活性是指對不斷變化的環境作出反應的能力。由于其整體風格(monolith)的性質,可能會變得難以應對通過所有層的變化,開發者需要注意依賴性和分層分離。

易于部署:大型應用程式的部署會是個麻煩。一個小要求,可能需要部署整個應用程式。如果能做好持續傳遞,可能會有所幫助。

可測試性:使用mocking和faking,每一層可以獨立測試,是以測試上很容易。

性能:雖然分層應用程式可能表現良好,但是因為請求需要經過多個分層,可能會存在性能問題。

可伸縮性:因為耦合太緊以及整體風格(monolith)的天生特質,很難對分層應用程式進行伸縮。然而,如果分層能夠被建構為獨立的部署,還是可以具備伸縮能力的。但是,這樣做的代價可能很昂貴。

易于開發:這種模式特别易于開發。許多企業采用這種模式。大多數開發者也都知道、了解,并且可以輕松學習如何使用它。

事件驅動架構(event driven architecture)是一種流行的分布式異步架構模式,用于建立可伸縮的應用程式。這種模式是自适應的,可用于小規模或者大規模的應用程式。事件驅動架構可以與調停者拓撲(mediator topology)或者代理者拓撲(broker topology)一起使用。了解拓撲的差異,為應用程式選擇正确的拓撲是必不可少的。

調停者拓撲需要編排多種事件。比如在交易系統中,每個請求流程必須經過特定的步驟,如驗證、訂單、配送,以及通知買家等。在這些步驟中,有些可以手動完成,有些可以并行完成。

通常,架構主要包含4種元件,事件隊列(event queue)、調停者(mediator)、事件通道(event channel)和事件處理器(event processor)。用戶端建立事件,并将其發送到事件隊列,調停者接收事件并将其傳遞給事件通道。事件通道将事件傳遞給事件處理器,事件最終由事件處理器處理完成。事件調停者不會處理也不知道任何業務邏輯,它隻編排事件。事件調停者知道每種事件類型的必要步驟。業務邏輯或者處理發生在事件處理器中,事件通道、消息隊列或者消息主題用于傳遞事件給事件處理器。事件處理器是自包含和獨立的,解耦于架構。理想情況下,每種事件處理器應隻負責處理一種事件類型。

通常,企業服務總線、隊列或者集線器可以用作事件調停者。正确選擇技術和實作能夠降低風險。

不像調停者拓撲,代理者拓撲不使用任何集中的編排,而是在事件處理器之間使用簡單的隊列或者集線器,事件處理器知道處理事件的下一個事件處理器。因其分布式和異步的性質,事件驅動架構的實作相對複雜。我們需要面對很多問題,比如網絡分區、調停者失敗、重新連接配接邏輯等。由于這是一個分布式且異步的模式,如果你需要事務,那就麻煩了,你得需要一個事務協調器。分布式系統中的事務非常難以管理,很難找到标準的工作機關模式。

另一個充滿挑戰的概念是契約。架構師聲稱服務的契約應該預先定義,而應變是非常昂貴的。

事件驅動架構分析:

靈活性:由于事件和事件處理器之間解耦,并且可獨立維護,是以這種模式的靈活性很高。變化可以快速、輕松地完成,而不會影響整個系統。

易于部署:由于架構是解耦的,是以很容易部署。元件可以獨立部署,并且可以在調停者上注冊。部署在代理者拓撲上也相當簡單。

可測試性:雖然獨立測試元件很容易,但測試整個應用程式很有挑戰。是以端到端的測試是很難的。

性能:事件驅動架構性能非常好,因為它是異步的。此外,事件通道和事件處理器可以并行工作,因為它們是解耦的。

可伸縮性:事件驅動架構的伸縮性非常好,因為元件之間解耦,元件可以獨立擴充。

易于開發:這種架構的開發不是很容易。需要明确定義契約,錯誤處理和重試機制得處理得當。

微核心架構(microkernel architecture)模式也被稱為插件架構(plugin architecture)模式。這是産品型應用程式的理想模式,由兩部分組成:核心系統和插件子產品。核心系統通常包含最小的業務邏輯,并確定能夠加載、解除安裝和運作應用所需的插件。許多作業系統使用這種模式,是以得名微核心。

插件彼此獨立,是以解偶。核心系統持有注冊器,插件将自己注冊其上,是以核心系統知道哪裡可以找到它們以及如何運作它們。這種模式非常适合桌面應用程式,但是也可以在web應用程式中使用。事實上,許多不同的架構模式可以作為整個系統的一個插件。對于産品型應用程式來說,如果我們想将新特性和功能及時加入系統,微核心架構是一種不錯的選擇。

微核心架構分析:

靈活性:由于插件可以獨立開發并注冊到核心系統,微核心架構具有很高的靈活性。

易于部署:依賴于核心系統的實作,能做到不需要重新啟動整個系統來完成部署。

可測試性:如果插件開發是獨立的,測試就可以獨立且隔離地進行。還可以mock核心系統來測試插件。

性能:這取決于我們有多少插件在運作,但性能可以調優。

可伸縮性:如果整個系統被部署為單個單元,這個系統将難以擴充。

易于開發:這種架構不容易開發。實作核心系統和注冊會很困難,而且插件契約和資料交換模型增加了難度。

盡管微服務的概念還相當新,但它确實已經快速地吸引了大量的眼球,以替代整體應用和面向服務架構(soa)。其中的一個核心概念是具備高可伸縮性、易于部署和傳遞的獨立部署單元(separately deployable units)。最重要的概念是包含業務邏輯和處理流程的服務元件(service component)。拿捏粒度設計服務元件是必要而具有挑戰性的工作。服務元件是解耦的、分布式的、彼此獨立的,并且可以使用已知協定來通路。

微服務的發展是因為整體應用和面向服務應用程式的缺陷。整體應用程式通常包含緊耦合的層,難以部署和傳遞。比如,如果應用程式總在每次應對變化時垮掉,這是一個因耦合而産生的大問題。微服務将應用程式分解為多個部署單元,是以很容易提升開發和部署能力,以及可測性。雖然面向服務架構非常強大,具有異構連接配接和松耦合的特性,但是成本效益不高。它很複雜、昂貴,難于了解和實作,通常對于大多數應用程式來說矯枉過正。微服務簡化了這種複雜性。跨服務元件的代碼備援是完全正常的。開發微服務時,為了受益于獨立的部署單元,以及更加容易的部署,我們可以違反dry原則。其中的挑戰來自服務元件之間的契約,以及服務元件的可用性。

微服務架構分析:

靈活性:由于服務元件可以各自獨立開發,彼此沒有耦合,是以微服務架構具有很高的靈活性。獨立部署單元能夠對變化作出迅速的反應。

易于部署:相比其他的架構模式,微服務的優勢是服務元件即是單獨部署單元。

可測試性:服務元件的測試可以獨自完成。微服務的可測試性很高。

性能:依賴于服務元件和這種特定模式的分布式性質。

可伸縮性:獨立部署單元天然具備很好的伸縮性。

易于開發:每個服務元件可以各自獨立實作。

《博文共賞》是infoq中文站新推出的一個專欄,精選來自國内外技術社群和個人部落格上的技術文章,讓更多的讀者朋友受益,本欄目轉載的内容都經過原作者授權。文章推薦可以發送郵件到[email protected]