借用當下最流行的段子作個開場白。前端
「設計原則千萬條,高內聚低耦合第一條,架構設計不規範,開發運維兩行淚!」。數據庫
在分佈式架構下,單體應用被拆分爲多個微服務,爲了保證微服務的單一職責和合理拆分,「高內聚、鬆耦合」是最寶貴的設計原則。後端
通俗點講,高內聚就是把相關的行爲彙集在一塊兒,把不相關的行爲放在別處,若是你要修改某個服務的行爲,最好只在一處修改。若是作到了服務之間的鬆耦合,那麼修改一個服務就不須要修改另外一服務,一個鬆耦合的服務應該儘量少的知道與之協做的那些服務的信息。設計模式
從集中式架構向分佈式架構的技術轉型,正如從蓋磚瓦房向蓋高樓大廈轉變同樣,必然要有組織、文化、理念和設計方法的同步更新,其中最不可或缺的能力就是架構設計能力。緩存
如何作到「高內聚、低耦合」?咱們先來學習幾種典型的微服務架構模型。安全
在整潔架構裏,同心圓表明應用軟件的不一樣部分,從裏到外依次是領域模型、領域服務、應用服務、最外圍是容易變化的內容,如界面和基礎設施(如數據存儲等)。整潔架構是以領域模型爲中心,不是以數據爲中心。性能優化
整潔架構網絡
整潔架構最主要原則是依賴原則,它定義了各層的依賴關係,越往裏,依賴越低,代碼級別越高。外圓代碼依賴只能指向內圓,內圓不知道外圓的任何事情。通常來講,外圓的聲明(包括方法、類、變量)不能被內圓引用。一樣的,外圓使用的數據格式也不能被內圓使用。數據結構
整潔架構各層主要職能以下:架構
Entities:實現領域內核心業務邏輯,它封裝了企業級的業務規則。一個Entity能夠是一個帶方法的對象,也能夠是一個數據結構和方法集合。
Use Cases:實現與用戶操做相關的服務組合與編排,它包含了應用特有的業務規則,封裝和實現了系統的全部用例。
Interface Adapters:它把適用於Use Cases和entities的數據轉換爲適用於外部服務的格式,或把外部的數據格式轉換爲適用於Use Casess和entities的格式。
Frameworks and Drivers:這是實現全部前端業務細節的地方:UI,Tools,Frameworks等。
追溯微服務架構的淵源,通常會涉及到六邊形架構。六邊形架構的核心理念是:應用是經過端口與外部進行交互的,這也是微服務架構下API網關盛行的主要緣由。六邊形架構中,內部業務邏輯(應用層和領域模型)與外部資源(APP,WEB應用以及數據庫資源等)徹底隔離,僅經過適配器進行交互。它解決了業務邏輯與用戶界面的代碼交錯的主要問題,從而能夠很好的實現先後端分離。
六邊形架構
六邊形架構將系統分爲內部和外部兩層六邊形,內部六邊形表明了應用的核心業務邏輯,外部六邊形表明外部應用、驅動和基礎資源等。內部經過端口和適配器與外部通訊,對應用以API主動適配的方式提供服務,對資源經過依賴反轉被動適配資源的形式呈現。一個端口可能對應多個外部系統,不一樣的外部系統使用不一樣的適配器,適配器負責對協議進行轉換。這就使得應用程序可以以一致的方式被用戶、程序、自動化測試、批處理腳本所驅動。
六邊形架構各層的依賴關係與整潔架構相似。
CQRS就是讀寫分離,讀寫分離的主要目的是爲了提升查詢性能,同時達到讀、寫解耦。而DDD和CQRS結合,能夠分別對讀和寫建模。
CQRS(命令與查詢職責分離)
查詢模型是一種非規範化數據模型,它不反映領域行爲,只用於數據查詢和顯示;命令模型執行領域行爲,在領域行爲執行完成後通知查詢模型。
命令模型如何通知到查詢模型呢?若是查詢模型和領域模型共享數據源,則能夠省卻這一步;若是沒有共享數據源,能夠藉助於發佈訂閱的消息模式通知到查詢模型,從而達到數據最終一致性。
Martin在blog中指出:CQRS適用於極少數複雜的業務領域,若是不是很適合反而會增長複雜度;另外一個適用場景是爲了獲取高性能的查詢服務。
對於寫少讀多的共享類通用數據服務(如主數據類應用)能夠採用讀寫分離架構模式。單數據中心寫入數據,經過發佈訂閱模式將數據副本分發到多數據中心。經過查詢模型微服務,實現多數據中心數據共享和查詢。
分層架構的一個重要原則是每層只能與位於其下方的層發生依賴。
分層架構的好處是顯而易見的。
首先,因爲層間鬆散的耦合關係,使得咱們能夠專一於本層的設計,而沒必要關心其餘層的設計,也沒必要擔憂本身的設計會影響其它層,對提升軟件質量大有裨益。其次,分層架構使得程序結構清晰,升級和維護都變得十分容易,更改某層的代碼,只要本層的接口保持穩定,其餘層能夠沒必要修改。即便本層的接口發生變化,也隻影響相鄰的上層,修改工做量小且錯誤能夠控制,不會帶來意外的風險。
關於分層架構的權威觀點,Martin Fowler在《Patterns of Enterprise Application Architecture》一書中給出了答案: 1. 開發人員只關注整個架構中的某一層。 2. 很容易的用新的方法來替換原有層次的方法。 3. 下降層與層之間的依賴。 4. 有利於標準化。 5. 利於各層邏輯的複用。
要保持程序分層架構的優勢,就必須堅持層間的鬆耦合關係。設計程序時,應先劃分出可能的層次,以及此層次提供的接口和須要的接口。設計某層時,應儘可能保持層間的隔離,僅使用下層提供的接口。
DDD(領域驅動設計)分層架構
DDD分層架構各層定義與職能:
展示層:它負責向用戶顯示信息和解釋用戶命令,完成前端界面邏輯。這裏的用戶不必定是使用用戶界面的人,也能夠是另外一個計算機系統。
應用層:它是很薄的一層,負責展示層與領域層之間的協調,也是與其它系統應用層進行交互的必要渠道。應用層要儘可能簡單,不包含業務規則或者知識,不保留業務對象的狀態,只保留有應用任務的進度狀態,更注重流程性的東西。它只爲領域層中的領域對象協調任務,分配工做,使它們互相協做。
領域層:它是業務軟件的核心所在,包含了業務所涉及的領域對象(實體、值對象)、領域服務以及它們之間的關係,負責表達業務概念、業務狀態信息以及業務規則,具體表現形式就是領域模型。領域驅動設計提倡富領域模型,即儘可能將業務邏輯歸屬到領域對象上,實在沒法歸屬的部分則以領域服務的形式進行定義。
基礎設施層:它向其餘層提供通用的技術能力,爲應用層傳遞消息(API網關等),爲領域層提供持久化機制(如數據庫資源)等。
雖然整潔架構、六邊形架構以及DDD分層架構三種架構模型展示方式以及解決問題的出發點不同,但其架構思想與微服務架構高內聚低耦合的設計原則高度一致。
整潔、六邊形以及DDD三種架構模型關係
突破現象看本質,在變與不變中尋找平衡!
從上圖能夠看出,在六邊形架構、DDD分層架構的白框部分以及整潔架構Use Cases和Entities區域實現了核心業務邏輯。可是核心業務邏輯又由兩部分來完成:應用層和領域層邏輯。領域層實現了最核心的業務領域部分的邏輯,對外提供領域模型內細粒度的領域服務,應用層依賴領域層業務邏輯,經過服務組合和編排經過API網關向前臺應用提供粗粒度的服務。
系統需求千變萬化,但變化老是有矩可循的,用戶體驗、操做習慣、市場環境以及管理流程的變化,每每會致使界面邏輯和流程的多變,但整體來講,無論前臺如何變化,核心領域邏輯基本不會大變。把握好這個規律,咱們就知道如何設計應用層和領域層,如何進行邏輯劃界了。
上述三種架構模型正是經過分層方式來控制需求變化對系統的影響,確保從外向裏受需求影響逐步減少。面向用戶的展示層能夠快速響應外部需求進行調整和發佈,靈活多變,應用層經過服務組合和編排實現業務流程的快速適配上線,領域層基本就不須要太多的變化了。這樣設計的好處是能夠保證領域層的核心業務邏輯不會由於外部需求和流程的變更而調整,對於創建前臺靈活、中臺穩固的架構能力是頗有好處的。
中臺和微服務設計的關鍵在於合理的分層和領域模型的設計!
聚焦領域模型
中臺屬於後端業務領域邏輯範疇,重點關注領域內業務邏輯的實現,經過實現公共需求爲前臺應用提供共享服務能力。按DDD的方法,在領域模型創建的過程當中會對業務和應用進行清晰的邏輯和物理邊界劃分。領域模型的設計結果會影響到後續的系統模型、架構模型和領域層代碼模型的設計,最終影響到微服務的拆分和項目落地實施。
合理的架構分層
不要把與領域無關的業務邏輯放在領域層,避免領域業務邏輯被污染,保證領域層的純潔,只有這樣才能下降領域邏輯受外部變化的影響。在領域和架構模型創建後,代碼模型的邏輯分層和微服務拆分要具體狀況具體分析,根據自身研發和運維能力綜合考慮。
(1) 項目級單應用
對於單應用系統的分層,遵循上述分層架構模型便可,核心領域邏輯在領域層實現,服務的組合和編排在應用層實現,二者組合造成中臺,經過API對前臺應用提供服務。
從部署和微服務拆分來說,領域層代碼部署時多是一個微服務,也可能會根據限界上下文被拆分爲多個微服務部署。應用層代碼若是邏輯複雜,含較多個性業務邏輯,能夠根據須要獨立爲微服務部署。若是邏輯簡單,且領域層是一個微服務,在劃分好應用層和領域層代碼邏輯邊界的狀況下,若是符合微服務拆分原則,也能夠考慮將應用層與領域層代碼合併爲一個微服務部署。
(2)企業級多中臺應用
對於企業級多中臺應用,多箇中臺應用經過API網關對外發布API服務。核心域業務中臺在調用支撐域和通用域中臺服務時經過核心域應用層完成多中臺服務的組合和編排,爲前臺應用提供API服務。核心域中臺的應用層是否獨立成微服務部署,需考慮的狀況與單應用系統類似。
服務的管理
應用層、領域層和基礎設施層都有對應的服務,各司其職提供服務,其中基礎設施層的服務經過依賴反轉模式爲領域層和應用層提供基礎設施資源服務。應用層和領域層服務發佈在API網關,經過API網關適配,爲前臺提供用戶無差別化(應用app、批處理或自動化測試)的服務。
資源的適配和解耦
因爲上述架構模型中定義的外層只能依賴內層的架構原則,對於像數據庫、緩存、文件系統等的外部基礎設施資源,每每採用依賴反轉的模式對外提供資源服務,實現應用層、領域層與基礎設施層資源的解耦。在設計中應考慮資源層的代碼適配邏輯,一旦基礎設施資源出現變動(如換數據庫),能夠屏蔽資源變動對業務代碼帶來的影響,切斷業務邏輯對基礎資源的依賴,下降因爲資源變動對業務邏輯的影響。
前臺應用
從核心業務邏輯來看,中臺實現了主要的業務邏輯,屬於標準化的重量級應用。前臺應用聚焦於界面交互以及業務流程等,屬於輕量級應用,前臺應用能夠有個性的業務邏輯、流程和配置數據,甚至數據庫,經過調用中臺API服務完成交互界面和業務全流程。
在單機和集中式架構時代,系統分析和設計每每都是分階段割裂進行的,容易致使需求、設計與代碼實現的不一致,軟件上線後才發現不少功能不是本身想要的,並且在這種模式下,軟件也不能快速響應需求和業務變化。
領域驅動設計(DDD)打破了這種隔閡,它提出了領域模型概念,統一了分析、設計和開發語言和過程,使得軟件可以更靈活快速響應需求變化。
軟件分析和設計方法經歷了三個階段的演進:
第一階段是單機架構時代:採用面向過程的設計方法,系統包括UI層和數據庫兩層,採用C/S架構模式,整個系統圍繞數據庫驅動設計和開發,新項目老是從設計數據庫及其字段開始。
第二階段是集中式架構時代:採用面向對象的設計方法,系統包括UI層、業務邏輯層和數據庫層,採用經典的三層架構,也有部分應用採用傳統的SOA架構,這種架構易使服務變得臃腫,難於維護拓展,伸縮性能差。這個階段系統分析、軟件設計和開發大可能是分階段進行的。
第三階段是分佈式架構時代:因爲微服務架構的流行,採用領域驅動設計方法,應用系統包括UI層、應用層、領域層和基礎層。這個階段融合了分析和設計階段,經過創建領域模型,劃分領域邊界,作到領域模型既設計,代碼與設計保持一致。
領域驅動設計主要優點:1.業務導向。2.業務邏輯內聚,應用邊界清晰。3.創建領域模型優先。4.分析、設計、代碼和數據有機結合。5.代碼即設計。6.擴展性好。
數據驅動設計主要特色:1.技術導向。2.數據庫優先。3.代碼不能反映業務和設計。4.業務邏輯分散。5.擴展性很差。
2004年Eric Evans 發表《Domain-Driven Design –Tackling Complexity in the Heart of Software》 (領域驅動設計 )簡稱Evans DDD。但在軟件開發領域一直都是雷聲大,雨點小,領域驅動設計核心思想是經過領域驅動設計方法定義領域模型,從而肯定業務和應用邊界,保證業務模型與代碼模型的一致性。這幾年之因此開始火起來,主要功勞要歸功於隊友「微服務」,領域驅動設計與微服務架構天生匹配。
領域驅動設計(DDD)是一種處理高度複雜域的設計思想,試圖分離技術實現的複雜性,圍繞業務概念構建領域模型來控制業務的複雜性,以解決軟件難以理解,難以演化等問題。團隊利用它能夠成功的開發複雜業務軟件系統,在系統變大時仍能保持敏捷性。
領域驅動設計分爲兩個階段:
1.以一種領域專家、設計人員、開發人員都能理解的通用語言做爲相互交流的工具,在交流的過程當中發現領域概念,而後將這些概念設計成一個領域模型;
2.由領域模型驅動軟件設計,用代碼來實現該領域模型。
領域驅動設計的核心訴求是讓業務架構和系統架構造成綁定關係,當咱們去響應業務變化調整業務架構時,系統架構的改變也會隨之發生。在領域驅動設計中業務架構的梳理和系統架構的梳理是同步進行的,其結果是設計出的業務上下文和系統模塊結構是綁定的。同時技術架構也是解耦的,能夠根據劃分出來的業務上下文的系統架構選擇最合適的實現技術。
領域驅動設計包括戰略設計和戰術設計兩個部分。戰略設計主要關注按領域定義,在限界上下文內造成統一語言,提高業務和技術的溝通效率; 戰術設計主要關注領域設計在落地時與設計模型及實現模型的差別性,減少業務和技術之間的鴻溝。(本文對DDD知識點不作詳述,如需瞭解或學習,請查閱《領域驅動設計:軟件核心複雜性應對之道》和《實現領域驅動》)。
領域驅動設計可能會給你帶來如下收穫:
一、領域驅動設計是一套完整而系統的設計方法,它能帶給你從戰略設計到戰術設計的規範過程,使得你的設計思路可以更加清晰,設計過程更加規範。
二、領域驅動設計尤爲善於處理與領域相關的高複雜度業務的產品研發,經過它能夠爲你的產品創建一個核心而穩定的領域模型內核,有利於領域知識的傳遞與傳承。
三、領域驅動設計強調團隊與領域專家的合做,可以幫助團隊創建一個溝通良好的團隊組織,構建一致的架構體系。 領域驅動設計強調對架構與模型的精心打磨,尤爲善於處理系統架構的演進設計。
四、領域驅動設計的思想、原則與模式有助於提升團隊成員的架構設計能力。
五、領域驅動設計與微服務架構天生匹配,不管是在新項目中設計微服務架構,仍是將系統從單體架構演進到微服務設計,均可以遵循領域驅動設計的架構原則。
領域驅動設計做爲一種架構設計方法,微服務做爲一種架構風格,二者從本質上都是爲追求高響應力目標而從業務視角去分離複雜度的手段。 二者都強調從業務出發,其核心要義強調根據業務發展,合理劃分領域邊界,持續調整現有架構,優化現有代碼,以保持架構和代碼的生命力(演進式架構) 。
領域驅動設計主要關注:業務領域,劃分領域邊界;構建通用語言,高效溝通;對業務進行抽象,創建領域模型;維持業務和代碼的邏輯一致性。
微服務主要關注:運行時進程間通訊,可以容錯和故障隔離;去中心化管理數據和去中心化治理;服務能夠獨立的開發、測試、構建和部署,按業務組織全功能團隊;高內聚低耦合,職責單一。
若是你的業務焦點在領域和領域邏輯,那麼你就能夠選擇DDD進行微服務架構設計。
中臺的定義來源於阿里的中臺戰略(詳見《企業IT架構轉型之道:阿里巴巴中臺戰略思想與架構實戰》鍾華編著)。2015年年末,阿里巴巴集團對外宣佈全面啓動阿里巴巴集團2018年中臺戰略,構建符合數字時代的更具創新性、靈活性的「大中臺、小前臺」組織機制和業務機制,即做爲前臺的一線業務會更敏捷、更快速適應瞬息萬變的市場,而中臺將集合整個集團的運營數據能力、產品技術能力,對各前臺業務造成強力支撐。
中臺的本質是提煉各個業務條線的共同需求,並將這些功能打形成組件化產品,而後以API接口的形式提供給前臺各業務部門使用。前臺要作什麼業務,須要什麼資源能夠直接找中臺,不須要每次去改動本身的底層,而是在底層不變更的狀況下,在更豐富靈活的「大中臺」基礎上獲取支持,讓「小前臺」更加靈活敏捷。
中臺戰略的主要目標是實現公共需求和功能的中臺化共享,減小重複建設和投入,爲前臺提供統一的一致服務。至於前臺應用是否能夠有數據庫?抑或採用什麼樣的開發技術,這些都不是重點,重點須要考慮的是那些公共需求和須要共享的功能是否經過中臺的方式被前臺使用了。
領域驅動設計中領域的定義:一個領域本質上能夠理解爲就是一個問題域,只要是同一個領域,那問題域就相同。因此只要咱們肯定了系統所屬的領域,那這個系統的核心業務,即要解決的關鍵問題、問題的範圍邊界就基本肯定了。領域的本質是問題域,問題域可能根據須要逐層細分,所以領域可分解爲子域,子域或可繼續分爲子子域。。。
在領域驅動設計中根據重要性與功能屬性將領域分爲三類子域,分別是:核心子域、支撐子域和通用子域。決定產品和企業獨特競爭力的子域是核心子域,它是業務成功的主要因素和企業的核心競爭力。沒有個性化的訴求,屬於通用功能的子域是通用子域,如登錄認證。 還有一種所提供的功能是必須的,但不是通用也不是企業核心競爭力的子域是支撐子域,如單證。
DDD:核心域、支撐域和通用域
中臺、領域以及微服務屬於不一樣層面的內容,稍做分解咱們理清他們之間的關係。
以保險領域爲例,業務中臺大體可分爲兩類:第一類是提供保險核心業務服務的專屬業務中臺(如承保、理賠等業務);第二類是支撐核心業務流程完成保險全流程的通用中臺(如主數據、客戶、用戶以及電子保單等)。
專屬業務中臺是保險企業的核心競爭力,對應DDD的核心子域。通用中臺對應DDD支撐子域和通用子域。不一樣領域可根據領域大小進一步細分多個子域,多個子域可對應到一個業務中臺,一個業務中臺也可能會分解成多個子域。
中臺、領域以及微服務
微服務是技術實現和部署的範疇,實現領域或中臺的業務邏輯,爲前臺應用提供服務。領域根據限界上下文能夠設計爲多個微服務,而若是限界上下文過大,一個微服務也可能會包含多個子領域。
中臺是由多個業務條線的共同需求所構成,是須要共享的業務功能和服務單元的集合,一箇中臺可由一個微服務來實現,也可根據領域驅動設計和微服務拆分原則細分爲多個微服務,多個微服務功能集合共同組成一箇中臺。
DDD設計包括戰略設計和戰術設計兩個部分。在戰略設計階段主要完成領域建模和服務地圖。在戰術設計階段,經過聚合、實體、值對象以及不一樣層級的服務,完成微服務的建設和實施。經過DDD能夠保證業務模型、系統模型、架構模型以及代碼模型的一致。
本部分主要討論領域設計方法,如對戰術設計和開發方法感興趣可查閱DDD戰術設計相關資料。
DDD領域設計過程包括產品願景、場景分析、領域建模和服務地圖階段,也可根據須要裁剪沒必要要的階段和參與角色。領域驅動設計通常經歷2-6周的時間,領域模型設計完成後,便可投入微服務實施。
一、產品願景
產品願景是對產品的頂層價值設計,對產品目標用戶、核心價值、差別化競爭點等策略層信息達成一致,避免產品在演進過程當中偏離方向。
階段輸入:產品初衷、用戶研究、競品知識和差別性想法 。
參與角⾊:業務需求方、產品經理、開發組長和產品發起人。
階段產出:電梯演講畫布。
二、場景分析
場景分析是針對核心用戶及頂層服務的一種定性分析,從⽤戶視角出發,探索問題域中的典型場景分析。同時也是從用戶視角對問題域的探索,產出問題域中須要支撐的場景分類及典型場景,用以支撐領域建模階段。
階段輸⼊:核⼼干係人和服務價值定位。
參與角色:產品經理、開發組長和測試組長。
階段產出:場景分類清單。
三、領域建模
領域建模是經過對業務和問題域進⾏分析,建⽴領域模型,向上經過限界上下⽂指導微服務的邊界設計,向下經過聚合指導實體的對象設計。領域建模主要採用事件風暴方法。
階段輸入:業務領域知識和場景分類清單。
參與角色:領域專家、架構師、產品經理、開發組長和測試組長。
階段產出:聚合模型和限界上下⽂地圖。
四、服務地圖
服務地圖是整個產品服務架構的體現。結合業務與技術因素,對服務的粒度、邊界劃分、集 成關係進⾏梳理,獲得反映系統微服務層面設計的服務地圖。
階段輸⼊:限界上下⽂地圖。
參與角⾊:產品經理、開發組長、測試組長和產品發起人。
階段產出:服務地圖。
在進行服務地圖設計時須要考慮如下要素:1. 圍繞限界上下⽂邊界。2. 考慮不一樣業務變化速度/相關度、發佈頻率。3. 考慮系統非功能性需求,如系統彈性伸縮要求、安全性要求和可⽤性要求。4. 考慮團隊組織和溝通效率。5. 軟件包限制。6.技術和架構的異構。
經過DDD戰略和戰術全流程設計可創建業務架構與系統架構的一一映射,保證業務和代碼模型的一致性。
DDD的業務架構與系統架構映射創建過程
前面咱們談到了DDD的分層架構,分層架構主要包括:展示層、應用層、領域層和基礎層(參考圖:DDD(領域驅動設計)分層架構),各層都有不一樣的服務,但因爲各層職責不同,服務目的和實現方式也存在差別。
一、應用層服務
應用層是很瘦的一層,其服務主要用來表述應用和用戶行爲。它主要負責服務的組合、編排和轉發,負責處理業務用例的執行順序以及結果的拼裝,拼裝完領域服務後以粗粒度的服務經過API網關向前臺應用發佈。經過這樣一種方式,隱藏了領域層的複雜性及其內部實現機制。 應用層除了定義應用服務以外,在這層還能夠進行安全認證,權限校驗,持久化事務控制或向其餘系統發送基於事件的消息通知。
二、領域層服務
領域層是較「胖」的一層,它實現了所有業務邏輯而且經過各類校驗手段保證業務正確性。業務邏輯包括:業務流程、業務策略、業務規則、完整性約束等。 當領域中的某個操做過程或轉換過程不是實體或值對象的職責時,便將該操做放在一個單獨的服務接口中,這就是領域服務,領域服務是無狀態的。
三、基礎設施層服務
基礎設施層服務位於基礎設施層,根據依賴倒置原則,封裝基礎資源服務,實現資源層與應用層和領域層的調用依賴反轉,爲應用層和領域層提供基礎資源服務(如數據庫、緩存等基礎資源),實現各層的解耦,下降外部資源的變化對核心業務邏輯的影響。
四、總結
應用層服務是展示層和領域層的橋樑,經過調用領域對象和領域層服務來表達用例和用戶故事。領域對象負責單一操做, 領域層服務用於協調多個領域對象共同完成某個業務操做。 應用服務原則上不處理業務邏輯,領域服務處理業務邏輯。
在領域模型設計時,咱們一般會根據限界上下文將領域分解成不一樣的子域,劃分業務領域的邏輯邊界。在限界上下文內不一樣的實體和值對象能夠組合成不一樣的聚合,從而造成聚合與聚合之間的邏輯邊界。通常來講,限界上下文能夠做爲微服務拆分的依據,而限界上下文內的聚合因爲其業務邏輯的高度內聚,也能夠根據須要將同一領域內的聚合業務邏輯代碼拆分爲微服務,聚合是領域中能夠拆分爲微服務的最小單元。
限界上下文與限界上下文之間以及聚合與聚合之間的邊界是邏輯邊界,微服務與微服務的邊界是物理邊界。邏輯邊界強調業務領域邏輯或代碼分層的隔離,物理邊界強調部署和運行的隔離。
微服務設計時是否必定要作到邏輯邊界與物理邊界一致?
邏輯邊界的劃分是否能夠細於物理邊界?
過分的微服務拆分會致使服務、安全和運維管理更復雜,領域之間的服務協同或應用層的處理邏輯更復雜,總之一句話就是:須要更高的研發技能要求和軟件維護成本。所以領域和代碼分層的邏輯邊界的細分是必要的,可是物理邊界不宜過細,也就是說在不違反微服務拆分原則的狀況下,不宜過分拆分微服務。
爲何要細分業務和代碼邏輯邊界?
在從單體向微服務演進後,隨着新需求的出現,新的微服務會開始慢慢的膨脹起來,有一天你會發現膨脹的微服務有一部分業務能力須要拆分出去時,若是沒有提早進行邏輯邊界的細分,微服務內代碼的過分耦合將會讓你無從下手,你是否還須要再作一次從單體向微服務的拆分?
若是你在微服務設計時已經根據業務領域邊界提早進行了領域代碼的分層和邏輯隔離,在微服務再次拆分時,分別對邏輯分離的領域代碼打包,同步進行數據庫拆分,就能夠快速完成微服務的拆分,而不須要重複從單體應用向微服務痛苦的演進過程。
固然,在同一個微服務內邏輯隔離的代碼,在內部領域服務之間調用以及數據訪問設計上須要有合理的鬆耦合的設計和開發規範,不然也不能很快的完成微服務再次拆分。
總之,咱們須要內外部邏輯邊界清晰的微服務,而不是從一個大單體重構爲多個小單體。
不少時候你們對微服務設計的理解都覺得只要最後肯定拆分出多少個微服務就能夠了,其實拆成多少個微服務並非微服務架構的要點。如何設計或拆分才能避免拆分出來的微服務不是小單體?這纔是全部微服務架構團隊須要關注和解決的問題,這也是DDD的價值所在。
要作微服務而不是小單體
評判微服務設計合理的一個簡單標準就是:微服務在隨着業務發展而不斷拆分或者從新組合過程當中不會過分增長軟件維護成本,而且這個過程是很是輕鬆且簡單的。
爲了方便在微服務變大時實現快樂的拆分和合並,在明確各層代碼職責後,咱們須要對微服務代碼合理分層和邏輯隔離,如下圖爲例對代碼分層和結構進行簡要說明。
基礎層代碼:本層主要包括兩類適配代碼:主動適配和被動適配。主動適配代碼主要面向前端應用提供API網關服務,進行簡單的前端數據校驗、協議以及格式轉換適配等工做。被動適配主要面向後端基礎資源(如數據庫、緩存等),經過依賴反轉爲應用層和領域層提供數據持久化和數據訪問支持,實現資源層的解耦。
應用層代碼:本層代碼主要經過調用領域層服務或其餘中臺應用層服務,完成服務組合和編排造成粗粒度的服務,爲前臺提供API服務。本層代碼可進行業務邏輯數據的校驗、權限認證、服務組合和編排、分佈式事務管理等工做。
領域層代碼:本層代碼主要實現核心的業務領域邏輯,須要作好領域代碼的分層以及聚合之間代碼的邏輯隔離。相關的開發方法請查閱DDD戰術設計相關資料,並遵循相關設計和開發規範。
代碼邏輯分層和結構
對代碼進行邏輯隔離和分層的主要意義在於:
一、避免各層代碼的交叉,保持領域代碼的純潔,保證中臺領域層業務邏輯的穩定。
二、業務和代碼模型的邏輯保持一致,有利於微服務的拆分和組合。
絞殺者模式
絞殺者模式相似建築拆遷,在新建築分階段建設完成入住後,分步拆除舊建築物。
「絞殺者模式」是在遺留系統外圍,將新功能用新的方式構建爲新的服務 。經過在新的應⽤中實現新特性,保持和現有系統的鬆耦合,隨着時間的推移,新的服務逐漸「絞殺」老的系統。以此逐步地替換原有系統。 對於那些老舊龐大難以更改的遺留系統,推薦採用絞殺者模式。
修繕者模式
修繕者模式相似文物修復,將存在問題的部分建築重建或者修復後,從新加入到原有的建築中,保持建築原貌。
「修繕者模式」是在既有系統的基礎上,經過剝離新業務和功能,逐步「釋放」現有系統耦合度,解決遺留系統質量不穩定和Bug多的問題。就如修房或修路同樣,將老舊待修繕的部分進行隔離,用新的方式對其進行單獨修復。 修復的同時,需保證與其餘部分仍能協同功能。 修繕模式適用於需求變動頻率不高的存量系統。
微服務拆分過程當中需嚴格遵照高內聚、低耦合原則,同時結合項目的實際狀況,綜合考慮業務領域、功能穩定性、應用性能、團隊以及技術等因素。
一、基於業務領域拆分,在領域模型設計時需對齊限界上下⽂,圍繞業務領域按職責單一性、功能完整性進行拆分,避免過分拆分形成跨微服務的頻繁調用。
二、基於業務變化頻率和業務關聯拆分,識別系統中的業務需求變更較頻繁的功能,考慮業務變動頻率與相關度,並對其進行拆分,下降敏態業務功能對穩態業務功能的影響。
三、基於應用性能拆分,考慮系統⾮功能性需求,識別系統中性能壓力較大的模塊,並優先對其進行拆分,提高總體性能,縮小潛在性能瓶頸模塊的影響範圍。
四、基於組織架構和團隊規模,提升團隊溝通效率。
五、基於軟件包大小,軟件包過大,不利用微服務的彈性伸縮。
六、基於不一樣功能的技術和架構異構以及系統複雜度。
企業一旦採用分佈式架構和微服務技術體系,在設計時須要關注商業模式、業務邊界、數據體系、微服務設計、前臺交互以及多活容災等多領域的協同。
一、數據是本難唸的經
分佈式架構下數據面臨的問題遠比集中式架構複雜。諸如:分佈式數據庫的選型、數據的分庫和分表、數據的同步與異步、跨庫和聯表查詢、數據的分佈與集中、在線業務數據與統計分析數據的協同、集中式數據庫向分佈式數據庫的遷移以及面向場景的集中數據複製等。
(1)分佈式數據庫的選擇
從集中式架構向分佈式架構轉型,第一步就須要考慮選擇什麼樣的分佈式數據庫。說到這裏我也給你們推薦一個架構學習交流圈。交流學習企鵝圈號:519752913,裏面會分享一些資深架構師錄製的視頻錄像:有Spring,MyBatis,Netty源碼分析,高併發、高性能、分佈式、微服務架構的原理,JVM性能優化、分佈式架構等這些成爲架構師必備的知識體系。還能領取免費的學習資源,目前受益良多
爲解決交易型分佈式數據庫的橫向計算能力,目前主要有三種類型的分佈式數據庫:一體化交易型分佈式數據庫方案(如阿里OceanBase和華爲高斯數據庫,多采用Paxos協議實現多副本數據一致)、單機交易數據庫加數據庫中間件方案(如騰訊TDSQL和TBase等,多采用數據同步實現多副本數據一致)和單機交易數據庫加分庫基礎類庫(如ShardingSphere等,主要實現數據路由和歸集)方案。三者的使用場景基本相同,都是經過對大表數據做水平切分,業務請求動態路由到指定節點,以此達到計算能力的線性擴展。一體化方案是以數據庫和中間件一體化產品的形式解決線性擴展問題,支持多副本,高可用,提供統一的運維界面。 數據庫中間件方案是以獨立數據庫中間件結合集中式數據庫的方式來解決線性擴展問題,高可用功能由中間件和數據庫自身功能分別保證。分庫基礎類庫方案是一種相似中間件的輕量級解決方案,適合簡單快速的交易操做,在強一致性和聚合分析查詢方面較弱。
(2)數據的分庫和分庫主鍵
選擇完分佈式數據庫後,第二步就須要考慮如何按照領域模型和微服務進行數據庫的分庫設計,選擇合適的分庫主鍵將是一個關鍵技術點。
對於與客戶接觸的業務領域,我的認爲能夠以客戶維度做爲數據分庫主鍵,以客戶爲實體,確保全部與本客戶接觸和服務的數據都在一個單元內,經過集中共享的中臺服務,爲全部渠道的客戶提供一致性體驗。若是後序管理流程須要基於區域管理要求,也能夠考慮在後序業務環節的數據庫中以區域維度做爲數據庫分庫主鍵,知足業務基於區域的管理要求。
如何將客戶維度的數據傳輸到以區域爲維度的數據庫中?咱們能夠考慮基於消息隊列的事件驅動模型。
系統若是作不到「以客戶爲中心」,又如何能實現「以客戶爲中心」的業務需求呢?
(3)高頻熱點數據的緩存
對於像產品基礎數據、主數據之類的熱點高頻訪問數據,在進行系統設計時需考慮將這些數據加載至緩存中,下降數據庫的壓力,對外提供高性能的數據訪問能力。
緩存技術的使用就像調味料同樣,投入小見效快,用戶體驗提高快。
(4)數據副本與跨庫聯表查詢
採用分佈式技術後,數據將碎片化,爲了減輕因爲跨庫以及聯表查詢給分佈式數據庫的壓力,須要創建多維的全局數據視圖(如客戶統一視圖、業務統計數據視圖等)和麪向具體場景的預處理好的數據聚合副本,提供複雜場景的數據查詢服務,減輕交易型數據庫的壓力。
全局數據視圖其數據來源於各業務條線的分佈式數據庫,從源端分佈式數據庫經過準實時的方式聚集(能夠基於數據庫日誌捕獲技術加消息隊列)。全局視圖的數據庫也能夠是分佈式數據庫,根據業務要求選擇合適的分庫主鍵進行數據重分佈。
對於分佈式數據庫跨庫關聯查詢性能低的問題,有兩種解決方案,根據具體場景採用合適的方案:
1)面向場景的數據副本查詢庫。將這些須要關聯查詢的數據副本集中存放在一個分佈式數據庫中。在進行數據聚集時,提早作好數據關聯處理(如多表數據合併成一個寬表),經過查詢微服務,專職提供關聯查詢服務。
2)小表廣播模式。有些業務場景中少許表(如用戶、機構表等)須要跟業務數據進行關聯查詢,這種場景能夠考慮在業務數據庫中新建一張複製表(無需所有字段,取必要字段便可),在主表發生變化時,能夠經過發佈訂閱的消息隊列模式刷新複製表的數據,保證數據的一致性。
(5)合理的數據冗餘
完成領域模型和微服務設計後,集中式數據庫的數據將被分散到不一樣微服務的分佈式數據庫中。數據實體的依賴關係將被打破,若是須要調用前序或後序微服務的數據實體(如:投保微服務生成的投保單、保單管理微服務的保單須要關聯投保單,理賠的報案須要關聯保單等,或電商業務中:銷售過程當中的商品、運輸過程當中的貨物須要關聯商品信息),這時候就會跨庫或者跨微服務調用了,必然影響系統性能。
如何處理這些跨微服務的關鍵實體數據?
最好的方式就是數據冗餘,將前序或後序環節的關鍵數據以數據清單複製表(只需必要的關鍵數據,不須要全部明細數據)的方式冗餘存儲。冗餘的好處是,前臺頁面能夠一次性獲取本領域實體數據和關聯實體清單數據,同時也能夠在本庫對關聯清單數據進行查詢。只有在須要獲取關聯實體數據明細時,才調用前序或後續微服務獲取全量數據。
合理的數據冗餘能夠減小跨庫查詢,提高系統性能。
(6)如何數據遷移?
從集中式數據庫向分佈式數據庫切換時,數據遷移的複雜度將大大增長。須要考慮如何進行數據遷移?現有技術條件下,是否是不作數據遷移也能夠無縫切換?
傳統集中式架構數據多集中在一個集中式數據庫中,數據關聯度高。
分佈式架構下,數據會隨着微服務而同步拆分,數據將變得碎片化,存在複製表,數據重分佈,數據關聯被打破,甚至還可能須要重建數據關聯。另外,分佈式架構的容災和多中心多活要求,數據遷移時還須要考慮數據的多副本和多中心的數據複製。分佈式架構下數據遷移的複雜度大增。
互聯網公司大多采用演進式架構模式,有計劃分階段的進行技術體系的升級,不少時候用戶無感知就完成了架構的升級。而傳統企業在作技術升級時如採用絞殺者重構模式,是否必需要作數據遷移?若是不作數據遷移是否也能夠順利切換?是否經過數據路由加全量數據視圖的方案就能夠不作數據遷移,實現新舊並存,無縫切換?數據切換方案須要詳細設計和慎重考慮(尚在考慮中,且聽下回分解)。
(7)數據的異步和同步
分佈式架構下事件驅動設計模式是經常使用的方法,經過基於消息隊列的發佈訂閱模式,能夠很好的實現業務異步化。非實時業務場景能夠採用事件驅動的模式實現異步化,減輕數據庫壓力。
也能夠經過異步模式實現準實時的數據讀寫分離,提升數據庫性能。
二、中臺和微服務要處理好邊界
條條道路通羅馬,無論走哪條路,憑感受或拍腦殼也能夠設計出微服務,拆分結果可能與按照DDD方法出來的結果相似。可是若是有好的理論和方法指導,不但作事情有矩可循的,並且能夠避免走彎路。因爲DDD在設計的時候已經作好了邏輯的邊界劃分,在微服務須要組合和從新拆分時也會變得容易得多。
仍是有必要提一下:中臺和微服務設計能夠借鑑DDD的設計原則和理念,不過戰術設計部分因爲過於複雜和學習成本太高,能夠參考使用。
三、前、中臺協同和前臺數據的按需加載
前臺應用將來可能多采用單頁面(SPA)的微前端(對應於微服務的前端展示,一個微服務對應一個微前端)方式,經過前端集成框架(相似門戶)實現多頁面組合,提供統一的用戶體驗,在微服務和數據庫設計時也須要協同考慮前端頁面邏輯。
爲減輕跨微服務的訪問,前端頁面展現時應以清單數據方式按需加載,後端數據設計時也應同步考慮如何組合前端數據展現。如須要展現明細數據,經過調用API服務的方式獲取全量數據,減小沒必要要的跨微服務調用。
另外,符合條件的應用也可考慮頁面的動靜分離和路由接入,將靜態頁面經過CDN的技術,部署在靠近用戶的機房,下降交互次數,減小跨廣域網訪問帶來的網絡延遲。
前端知識有限,就寫這麼多了,哈哈。
四、容災和多活的全局考慮
分佈式架構的高可用是在應用、數據和基礎設施的分佈式技術升級後,經過多數據中心協同來實現的。
爲了容災和多活,在設計方面須要考慮:1)合適的分佈式數據庫。2)合理的數據分庫主鍵設計,數據的多副本和同步技術。3)單元化架構設計,處理好通用中臺和專屬中臺的部署和依賴關係,實現業務的自包含,減小跨數據中心調用。4)訪問層的接入,對外部訪問進行路由、限流以及灰度發佈。5)統一的全局配置數據,每一個數據中心都有實時同步的全量配置數據,實現容災和多活的一鍵切換。
五、避免過分拆分和硬件依賴
過分過細的微服務拆分帶來更多的軟件維護成本和運維壓力,過多的分佈式事務也會帶來性能和數據一致性的壓力。在進行設計時,要在保證邏輯邊界清晰的狀況下,嚴控微服務的過分拆分和採用過多的分佈式事務。
分佈式架構的自動的彈性伸縮大可能是經過軟件的方式去實現的,爲保證應用的彈性伸縮能力,在設計中應實現去硬件的無中心化(如可採用軟負載,就不用F5之類的硬負載),儘可能經過軟件實現彈性伸縮。由於一旦綁定硬件設備,在硬件遇到瓶頸須要自動彈性伸縮的時候,就須要人工干預,沒法自動彈性伸縮。
正如老馬說的採用微服務的企業需具有必定的高度,如文化、組織和技術,DDD一樣也須要站必定的高度。若是高度不夠,咱們是否能夠站在巨人的肩上呢?
在領域模型和微服務設計時,守住領域模型和邊界,各司其職,才能長治久安!
謹記:邊界!邊界!邊界!