如何在不重構的情況下將單體拆分成微服務?

banq發表於2022-12-10

微服務在過去幾年獲得了很大的普及,並且對我作為全棧開發人員的工作產生了很大的影響。但這些年來,我從未對單體失去信心。微服務帶來了很多額外的複雜性,在我所見的大多數情況下,這些複雜性並沒有超過它們帶來的價值。所以,我總是發現自己提倡和捍衛單一的方法。這引起了很多討論。

對我來說,單體架構微服務架構並沒有什麼不同。如果處理得當,單體應用由具有強大邊界的模組組成。這給模組結構帶來了高內聚和低耦合,使應用程式更易於維護和更改。它還允許多個團隊在同一應用程式上工作,而不會互相絆倒。這是我多次聽到的支援微服務的論點。

在設計應用程式時,我發現很難定義正確的邊界。無論它們是用於設定模組還是微服務。微服務有一些常見的分解模式,我發現它們同樣適用於單體應用。對於大多數情況,按業務能力進行分解是一個很好的起點。

例如,小型線上商店的基本結構可能如下所示:

如何在不重構的情況下將單體拆分成微服務?

模組化整體的想法絕對不是新的,但作為與微服務的對立而獲得更多關注。像Sam Newman這樣的專家寫了很多關於這個主題的文章,新技術從這些想法中誕生。一個很好的例子是用於 Java 應用程式的Spring Modulith專案。對於我工作過的大多數公司來說,這種型別的單體應用已經綽綽有餘了。

在我看來,微服務架構只是單體架構的分散式變體。分散式系統既不簡單也不便宜,所以選擇它一定有很好的理由。更好的應用程式結構或多團隊支援對我來說不算是好的論據。重要的是與運維相關的原因,如可伸縮性、可靠性和可部署性。

如果模組邊界足夠強大,將模組化單體重構為微服務應該相當容易。模組可以一個接一個獨立重構。

在對我們的小型線上商店進行全面重構後,應用程式可能看起來像這樣:

如何在不重構的情況下將單體拆分成微服務?

有許多方法(模式)來組織一個微服務架構。沒有一個放之四海而皆準的解決方案,所以正確的選擇總是取決於環境。例子中使用的API閘道器模式對於解耦服務、解決安全問題和其他問題都很好。它適合我作為大多數情況下的一個偉大的起點。

從單體開始,逐步重構為微服務,聽起來是一個很好的解決方案,但根據我的經驗,並不是非常實用。將一個模組重構為一個服務仍然需要大量的努力。設定一個新的專案,端點,請求,操作等等。一旦應用程式的列車執行,當客戶不斷要求新功能時,很難找到資源把它放在另一條軌道上。當等待的時間過長時,事情就開始分崩離析,氣氛迅速轉變。

這讓我開始思考。在理想的世界裡,一個單體可以過渡到微服務而不需要任何重構:
定義什麼在哪裡執行應該是一個配置問題,而且可以隨時改變。
我喜歡這個想法,但如何在不觸及程式碼的情況下將模組轉變為服務呢?

基於段Segment概念
在這個時候,我已經在研究一個可以幫助回答這個問題的概念:

作為一個全棧開發者,我花了相當多的時間來設定前端和後端之間的通訊,這總感覺是一個很大的開銷。
自動化兩端通訊是一個選項,將通訊從程式碼中轉移到執行時中。
透過這個解決方案,前端可以直接匯入和呼叫後端元件。執行時攔截所有的後端匯入,建立並提供一個遠端實現,就像一個依賴性注入器。

使用這種解決方案進行模組間的通訊解決了自動過渡到服務的問題。但執行時被限制在一個單一的前端和後端部分。因此,它已經被重構,以支援無限量的段,可以單獨或作為一個組部署到前端或一個或多個後端。一個段包含來自一個或多個模組的一個或多個元件。它的內容是由配置定義的

每個模組都放在一個單獨的段中。交付部分需要負載平衡(由於跟蹤功能)並部署到多個伺服器。其餘部分被分組並一起部署到單個伺服器。
或者,模組可以放置在單個段中,稍後移動到單獨的段。因為段僅存在於配置中,所以將模組移動到另一個段對程式碼沒有影響。這樣,無需重構即可即時重新安排應用程式。

執行時已成為在 MIT 許可證下發布的開源專案。它的名字叫Jitar,是Just-In-Time-Architecture的縮寫。由於全棧支援,它被實現為 Node.js 之上的一個層。所以它只適合 JavaScript 和 TypeScript 應用程式。儘管我認為同樣的事情可以用 Java(也許還有 .NET?)來實現。

GitHub 儲存庫
 

相關文章