六邊形架構:使用事件驅動的無伺服器實現松耦合 - Ellerby

banq發表於2022-01-12

當我們使用領域驅動設計構建事件驅動的無伺服器架構時,我們最終會得到一組服務,這些服務清楚地按業務功能劃分,並透過事件通道(例如 Amazon EventBridge)進行非同步通訊。這些架構帶來了許多優點:鬆散耦合、獨立可部署性、可測試性和降低複雜性等等。
然而,無論我們對領域的建模多麼優雅,總有一些跨領域的基礎設施依賴(例如事件通道本身)是無法消除的。
我們如何處理它們決定了我們是否得到一個鬆散耦合的烏托邦,或者一個雜亂無章的半獨立服務。當你付出了 90% 的努力後,不要讓這成為最後的絆腳石。
在本文中,我們將看到明確定義的服務埠如何解決最後 10% 的基礎設施依賴關係,並帶來鬆散耦合、獨立部署/測試和提高開發速度。
 

跨領域的基礎設施依賴關係
我們之前已經討論過如何將 Amazon EventBridge 與強大的領域驅動設計相結合來建立此類架構(請參閱EventBridge Storming)。當我們以這種方式構建服務(或“微服務”)集合時,仍然存在一些跨領域的全域性依賴關係。這些依賴項妨礙了獨立開發服務,使整合測試變得困難,並且可以在我們的基礎設施定義中建立複雜的程式碼。此外,當這種依賴關係不明確時,服務的部署順序充其量可能成為一個謎,最壞的情況是一組競爭條件。
為了使這一點更加具體,讓我們假設我們進行了一個EventBridge Storming 會話,透過將系統的所有業務事件收集到有界上下文中來了解電子商務網站的示例問題域。透過本次會議,我們將瞭解業務領域、屬於它的事件以及如何將它們組合在一起。
但是出現了問題:跨領域的基礎設施依賴關係
例如:

  • 我們可以在財務服務中實現這種複雜依賴關係的定義,並在人力資源服務中引用它。當它是 2 個服務時很好,但是 10 個服務都需要這個資源呢。
  • 人力資源服務的獨立開發現在不再可能。公司的任何新開發人員都必須先部署自己的財務服務版本,然後才能在 HR 服務上進行開發——或者他們依賴於臨時版本,可能無法直觀地理解原因。
  • 如果你不能獨立測試,你就不應該獨立部署。人力資源服務的獨立可測試性現在是不可能的;同樣,我們需要部署一個獨立的財務服務,或者冒著共享暫存資源不受控制的環境的風險——即使這些都是按使用付費和快速部署的無伺服器服務。

 

六邊形架構
埠和介面卡,或六邊形架構,是一種嘗試使依賴項可互換的方法。可互換的方面允許簡化開發和測試。此外,明確的埠規範可確保明確定義依賴關係。元件將它們的連線列為埠,並帶有它們期望的協議的 API 規範。然後一個或多個介面卡可以實現該協議。
回到我們的財務服務示例。此服務依賴於 EventBridge 匯流排和 Cognito 使用者池。但是這些依賴項應該放在哪裡呢?
如果他們使用一項服務,例如財務服務,他們將與它一起部署——但這是正確的嗎?不,僅僅因為財務服務發生了變化,並不意味著應該部署 EventBridge 或 Cognito 使用者池。
六邊形架構的埠設計已經減輕了一些可能會產生的相互依賴,但這並不意味著我們應該隨意選擇一個主機服務。相反,我們應該將這些視為服務,非常簡單的服務,因為我們的雲提供商透過事件匯流排和使用者身份驗證為我們提供了抽象。
建立一個“全域性”或“中央”或“基礎設施”中心並將任何橫切依賴項轉儲到其中是很誘人的,但是要避免這種誘惑。
正確遵循六邊形架構的設計是:
將“EventBridge 匯流排和 Cognito 使用者池”視為基礎架構,非業務領域部分。
開發人員在構建他們微服務時,包括上述財務服務時,需要透過手動或使用指令碼部署 EventBus 和 UserPool。
這些指令碼可以作為 CI/CD 管道的專用部分,或者甚至更好地作為基礎設施即程式碼模板中的條件塊(如果開發,如果測試,如果生產)。或輕鬆整合到 sls-test-tools 等工具進行整合測試
 

你不能避免所有的基礎設施依賴——但你可以選擇如何處理它們
強大的領域驅動設計和事件驅動的面向服務的架構在幫助確保可管理和鬆散耦合的架構方面大有幫助。但是,會出現一些跨領域的基礎設施依賴關係並模糊服務邊界。如果這些不明確和孤立,它們會對系統設計、耦合、認知負載和部署順序產生巨大影響。
採用具有明確服務埠的六邊形架構方法,我們可以將這些明確化,並從部署、測試和開發中消除跨服務依賴關係。
我們應該使用 DDD 來避免依賴,但不要隱藏我們擁有的依賴。如果存在真正的基礎設施依賴(例如事件匯流排、使用者身份),我們應該為其設計——確保它不會開啟通往復雜分散式單體應用的閘門。此外,不要將這些隱藏在任意主機服務中,而是建立小型、簡單和有目的的服務來包含這些依賴項的配置、部署和測試。
 

相關文章