大型系統應用邊界設計原則與實踐

danny_2018發表於2023-04-24

我曾經擔任某央企千萬級生產系統交付方的首席架構師,負責整個系統的架構設計和架構管理。整個專案主要由三家公司、四個團隊構成(各個團隊下還有各自的子團隊),團隊人數規模大約100人。

交付模式

整個專案的交付過程以我定義的所謂“大瀑布+小敏捷”模式開展,該模式的具體形式如下圖所示:

之所以採用這一方式,在於專案的每個里程碑節點必須按照合同約定的時間交付,例如在系統設計階段結束時,必須交付概要設計說明書等交付物,然而,專案組又不可能完全依據瀑布方式開展工作,否則交付風險為顯著增加,就需要有選擇地進行敏捷迭代開發。

如何將瀑布流程與敏捷流程有機地結合起來,確實是專案組必須面臨的挑戰。我之所以定義這一混合模式,固然是為了各取所長,但其起因還在於專案的交付模式。甲方客戶作為一家大型央企,必然重視流程管理與合同履約,該交付專案規模龐大,屬於甲方客戶極為重視的戰略專案,客戶的IT部門必須重度參與到管理流程中,透過跟蹤專案計劃的制訂與執行來跟蹤進度。

實際驗證,“大瀑布+小敏捷”相結合的混合模式在面對這樣的客戶和專案時,確實發揮了巨大的作用。我想,若有機會,我會撰寫單獨的文章詳細闡釋我提出來的這一方法。

架構管理

作為首席架構師,除了主導整個專案的整體架構設計,並對關鍵問題做出技術決策之外,還需要負責技術管理。為此,我組建了架構師團隊,團隊成員同時擔任各個團隊的技術負責人。我還建立了架構CoP(Community Of Practice)機制,透過定期召開架構CoP會議,跟蹤專案組面臨的技術問題,識別技術風險並給出相應的解決方案。

四個團隊分別位於成都、北京、杭州,這樣的分散式團隊需要透過線上會議進行溝通,溝通成本極大。架構CoP在執行一段時間後,我發現相當多爭執不休乃至懸而未決的問題出在對應用邊界的定義上,這一問題在微服務架構之上體現得尤為明顯。

微服務架構

整個系統採用瞭如下所示的微服務架構:

微服務架構採用了前後端分離的整體架構,後端的微服務層按照領域邊界劃分子領域,在各個子領域內部,則根據業務的邊界識別微服務,對外提供客戶端需要的業務能力。每個微服務都是一個相互獨立完整的業務單元,其邏輯邊界也包括支撐該業務所必須的外部資源,包括資料庫、檔案或訊息佇列等。

客戶端層根據UI呈現方式與載體的不同分為Web前端、APP前端、其他智慧終端等。原則上,設計時需要保證前端的輕量級,儘量避免在前端編寫業務邏輯,目的在於:

前端資源有限,不利於處理複雜的業務邏輯

不同前端需要支撐的業務邏輯可能相同,如果在前端編寫業務邏輯,會導致業務實現的重複

遵循“輕前端、重後端”的思路,在進行產品設計與業務分析時,應確保前端邏輯與後端邏輯的邊界,並儘可能識別多個前端可以重用的業務邏輯,將其沉澱到後端的微服務層。

然而,客戶端層的前端與後端的微服務層往往不能做到完全的一一對應,因為前端的劃分依據是根據前端型別與使用者體驗進行劃分的,後端的劃分依據則是從領域維度與業務能力。

設計微服務公開的介面時,應從業務能力的角度定義,如此才能保證服務介面的重用粒度。根據這一設計原則定義的服務介面可能無法滿足前端UI的呈現目標,當後端微服務還需要支援不同的前端時,這一矛盾就更加突出。

微服務的服務介面既然是為了滿足業務能力設計的,就需要遵循“單一職責原則”,保證每個服務是正交的。對於前端的呈現邏輯而言,可能需要匯聚多個業務方向的資料,以降低使用者操作的複雜度。對於前端的使用者體驗而言,後端微服務定義的單個服務介面可能無法滿足前端的一次呼叫需求。

要解決這兩個問題,在架構上的做法就是在微服務層與客戶端層之間再引入一個間接層,它所處的位置屬於後端,但設計的介面卻完全是為前端服務的,因而被稱為“BFF(backend for frontend)層”。它的主要功能包括:

UI適配:呼叫後端微服務,將微服務返回的響應訊息轉換為支援多個前端呈現的檢視模型

服務聚合:定義一個外觀服務,內部發起對多個微服務介面的呼叫,然後將它們各自返回的資料聚合為一個整體的檢視模型

BFF層與API閘道器共同組成微服務應用架構的邊緣層。

康威定律

一個好的開發團隊與設計良好的架構應該遵循“康威定律”,也就是一個設計良好的系統,其架構的組織應該與開發它的團隊組織保持一致。因此,要與微服務的應用架構相對應,就應該建立如下所示的團隊組織:

遵循前後端分離的原則,通常需要為前端和後端建立不同的團隊。在後端的微服務層中,各個子領域專案可以根據微服務的邊界與團隊規模,以微服務為邊界組建特性團隊。之所以子領域的邊界沒有貫穿前端團隊,主要在於前端的邊界劃分並沒有遵循子領域的邊界,前端對後端微服務的呼叫,存在跨子領域呼叫的場景。

如果遵循康威定律,BFF層(邊緣層的API閘道器屬於微服務元件的範疇,無需單獨開發,故而不考慮在內)也需要建立一個單獨的團隊。但是在實際情況下,該團隊的建立需要考慮兩個因素:

交流成本

技能要求

從交流的頻率看,BFF與前端團隊的交流更加頻繁,為了降低交流成本,可考慮將BFF層的開發職責放到前端團隊;從技能要求看,前端團隊主要掌握JS技術棧,除非BFF的實現選擇NodeJS,否則仍然需要將實現交給後端團隊,這實際上是技術實現對邊界的影響。

多團隊協作的職責邊界

組建團隊時,團隊的邊界既是業務的邊界,又是職責的邊界。由於整個專案的參與方牽涉到三家公司的四個團隊,且這些團隊參與到專案的時間並不一致,要規避應用邊界的問題,就必須為各個團隊定義清晰的職責。

由於我們採用領域驅動設計方法定義子領域,這四個粒度較大的團隊實際對應於整個應用架構的子領域,因此,可以結合子領域的型別與範圍為團隊規定各自的職責範圍:

每個團隊都有自己的前端(或微前端)與後端,共同實現垂直領域的完整業務功能。

多團隊協作的資料邊界

除業務邊界外,組建團隊時還需要考慮資料的邊界,下圖體現了資料儲存和管理的範圍:

由上圖可知,移動App對應的移動子領域並未儲存和管理業務主資料,它如果需要獲得資料,需要呼叫業務A和業務B對外公開的服務。

應用邊界設計原則

應用架構的邊界受到業務邊界、資料邊界、團隊邊界、技術邊界多個方面的影響,必須控制邊界,否則會帶來設計與開發的混亂,影響團隊之間的協作。由此,這是我在參與多次架構CoP會議得到的親身感受。

應用邊界設計原則

為了避免大量類似問題的重複出現,也為了減少不必要的工作糾紛,我根據微服務的設計原則與團隊的組建原則,結合專案的實際情況,確定瞭如下應用邊界設計原則。

業務的邊界與資料的邊界儘可能保持一致,應保證“誰擁有資料,即由誰訪問資料”。例如,資料平臺擁有全域分析資料,則由資料平臺提供分析業務功能;業務A與業務B分別提供與其業務資料對應的業務功能,移動App沒有業務資料,不提供訪問業務資料的業務功能。

業務的邊界與職責和能力的邊界儘可能保持一致,一個業務功能的邊界可以參考團隊職責範圍對其進行界定。例如,簡訊通知業務屬於跨領域的公共服務,應交由業務A團隊負責;資料平臺的監控功能屬於資料平臺的管理服務,應交由資料平臺團隊負責;掃描二維碼是移動APP才具備的能力,應交由移動App團隊負責。

BFF層UI適配和服務聚合功能的劃分取決於它所服務的前端。倘若它僅服務於移動APP和智慧終端前端,原則上應由移動App團隊負責;反之,應根據業務邊界和職責邊界,確定由除移動子領域之外的其他子領域團隊負責。

服務介面設計原則

介面設計的不確定性也會影響到應用邊界。每個服務介面都有服務提供方和消費方,若能定義一些普適性且具有實證主義的服務介面設計原則,就能清晰地規定各自職責,避擴音供方和消費方的相互推諉。以下是我給出的服務介面設計原則。

微服務對外定義的查詢介面應確保其擴充套件性,即只需為服務介面提供一個實現以支援不同的查詢條件與排序條件。原則上,查詢介面在返回列表資料時,應支援分頁能力。

服務介面的設計應遵循單一職責原則,對外提供高內聚的業務能力,保證服務介面彼此之間是正交的。如果呼叫者需要多個業務能力支援,以返回一個粗粒度的聚合資料,那麼該服務屬於服務聚合的範疇,應定義為一個對客戶端公開的外觀服務,放在BFF層。

服務介面的通用性優於專有性。例如,設計查詢某資源的服務介面時,應考慮到多個客戶端的呼叫請求,提供儘可能全面的資源資訊,服務的呼叫者可以根據自身要求選擇使用返回的對應資料,如此就可以透過增加服務介面的粒度來減少介面的數量。

開發團隊在確定業務功能的應用邊界時,應遵循以上原則,保證各個開發團隊能夠各司其職,以良好協作的方式完成業務功能的開發。如果存在業務功能的邊界劃分不適用於以上任何原則,或者對原則的適用存在分歧,則由架構師團隊召集相關團隊負責人進行討論,根據具體的應用場景確定最佳的解決方案。

來自 “ DevOps ”, 原文作者:張逸;原文連結:https://mp.weixin.qq.com/s/23fbVSJhK-e-gGMJ2nuAgw,如有侵權,請聯絡管理員刪除。

相關文章