單體到微服務最佳實踐
在本文中,我們將學習如何使用設計模式、原則和最佳實踐來設計微服務架構。我們將使用適當的架構設計模式和技術。
在本文結束時,您將瞭解如何通過設計系統來處理數百萬個請求,以在微服務分佈式架構上實現高可用性、高可擴展性、低延遲和網絡故障恢復能力。
事件驅動架構
本課程將是一個循序漸進的軟件架構設計之旅,從單體架構演變爲事件驅動的微服務架構。
我們將從軟件架構的基礎開始,設計可以處理少量請求的單一電子商務架構。
設計架構之旅
之後,架構將逐步演進如下:
-
分層架構
-
面向服務的架構 (SOA)
-
微服務
-
最後是事件驅動的微服務架構
最終狀態將提供按照這種方法處理數百萬個請求的能力。
概覽
本文將提供理論和實踐信息。
-
我們將學習一個特定的模式,爲什麼以及我們應該在哪裏使用
-
之後,我們將看到應用這些模式的參考架構
-
之後,我們將通過一起應用這個新學習的模式來設計我們的架構
-
最後,我們將根據這些架構決定使用哪些技術。
因此,我們將從單體架構迭代並演進到事件驅動的微服務架構。
演進的架構
我們將根據以下問題改進這些架構:
-
我們如何擴展應用程序?
-
我們的應用程序需要處理多少請求?
-
我們的架構可以接受多少秒的延遲?
因此,我們根據以下問題演變這些問題:
非功能性需求
可擴展性和可靠性是衡量您的應用程序爲最終用戶服務的表現的指標。如果我們的電子商務應用程序可以在不出現明顯停機的情況下處理數百萬用戶,那麼我們可以說該系統具有高度可擴展性和可靠性。可擴展性和可用性可能是設計良好架構時的相關特徵。
非功能性要求:
-
可擴展性:電子商務應用程序應該能夠爲數百萬用戶提供服務
-
可用性:電子商務應用程序應該 24/7 全天候可用
-
可維護性:電子商務應用程序的維護不應該很複雜。
-
效率:電子商務應用程序應以可接受的延遲響應,小於 2 秒。
每秒請求和可接受的延遲
好的,讓我們談談可接受的延遲;如果我們的應用程序被越來越多的用戶使用,我們如何才能使我們的應用程序具有可接受的延遲?
有關詳細信息,請參見下表:
每秒請求和可接受的延遲
正如您在表中所見,我們將啓動一個小型電子商務應用程序,該應用程序每秒僅獲得 2.000 個併發用戶和 500 個請求。
我們將根據這些預期數量設計我們的電子商務架構。
之後,當我們的業務增長時,將需要更多的資源來滿足更多的請求,我們將看到如何根據這些數字改進我們的架構。
單體架構
許多方法和模式在數十年的軟件開發過程中演變而來,它們都有好處和挑戰。
因此,我們將開始瞭解現有的方法來構建我們的電子商務應用程序、發展並將其轉移到雲中。要了解雲原生微服務,我們需要了解什麼是單體應用程序以及它們如何引導我們從單體服務轉向微服務。
單體架構
談到遺留應用程序,我們可以說大多數遺留應用程序都是作爲單體架構實現的。
如果所有項目功能都存在於單個代碼庫中,則該應用程序被稱爲單體應用程序。整體模式包括同一代碼庫中的用戶界面、業務代碼和數據庫調用的所有內容。
所有應用程序工件都包含在一個巨大的部署中。即使是單體應用程序也可以在不同的層進行設計,例如表示層、業務層和數據層,然後將該代碼庫部署爲單個 jar/war 文件。
我們將在後面討論的單體方法有幾個優點。但讓我詳細說明一些主要優點和缺點:
-
由於它是一個單一的代碼庫,因此很容易拉取並啓動一個項目。
-
由於此項目結構包含在一個項目中,並且易於調試跨不同模塊的交互。
-
由於活動部件較少,維護和故障排除的複雜性也較低。
不幸的是,單體架構有很多缺點,我們可以列出其中的一些:
-
隨着時間的推移,代碼量會變得太大;管理具有挑戰性。
-
很難在同一個代碼庫中並行工作。
-
難以在遺留的大型單體應用程序上實現新功能
-
任何更改都需要部署整個應用程序的新版本,等等。
如您所見,我們更好地理解了單體架構的優缺點。
何時使用單體架構
單體架構有很多缺點,但如果您正在構建一個小型應用程序,單體架構是您可以應用於您的項目的最佳架構之一。因爲,在很多方面,單體應用程序很簡單。
單體架構爲以下方面提供了簡單性:
-
構建
-
測試
-
部署
-
疑難解答
-
垂直縮放(放大)
與微服務相比,它的開發很簡單,微服務需要熟練的開發人員來識別和開發服務。它更容易部署,因爲只有一個 jar/war 文件可用於部署完整的應用程序。
設計單體架構
在本節中,我們將逐步使用單體架構設計我們的電子商務應用程序。我們會根據需求一個一個的迭代架構設計。
我們應該始終從寫下 FR(功能需求)和 NFR(非功能需求)開始。
功能要求
-
列出產品
-
按品牌和類別過濾產品
-
將產品放入購物車
-
申請折扣券並查看購物車中所有商品的總費用
-
檢查購物車並創建訂單
-
列出我的舊訂單和訂單項目歷史
非功能性需求
-
可擴展性
-
由於併發用戶的增加,性能可接受
此外,最好將原則添加到我們的圖片中,以便始終記住它們。
原則
-
KISS——保持簡單,愚蠢
-
YAGNI——你不會需要它
我們將在設計架構時考慮這些原則。
設計單體架構
如您所見,我們使用單體架構設計了我們的電子商務應用程序。
我們增加了電子商務大盒子;這些是我們的電子商務應用程序的組件:
-
購物界面
-
目錄服務
-
購物車服務
-
折扣服務
-
訂購服務
如您所見,此傳統 Web 應用程序的所有模塊都是容器中的單個工件。
這個單體應用程序有一個包含所有模塊的龐大代碼庫。
如果您向該應用程序引入新模塊,則必須對現有代碼進行更改,然後將具有不同代碼的工件部署到應用程序服務器,例如 Tomcat 服務器。我們遵循我們的 KISS 原則,即保持簡單。
我們將根據要求重構我們的設計,並逐步迭代。
單體架構的可擴展性
從下圖中可以看出,我們通過添加兩個應用程序服務器並在客戶端和電子商務應用程序之間的單體應用程序前面放置一個負載均衡器,通過水平擴展對單體架構進行了擴展。
爲了在單體架構上提供可擴展性,我們需要增加電子商務應用程序服務器的實例數量,並在我們的應用程序前面提供一個新的負載平衡器。
Load Balancer 將使用一致的分配算法容納請求並將請求發送到我們的電子商務應用程序服務器。此功能將爲服務器提供平均負載。
適配技術棧
我們將做出一些技術選擇——適配技術棧。
從圖中可以看出,我們已經爲我們的整體電子商務應用程序選擇了可能的選項。NGINX 是負載平衡的絕佳選擇,Oracle Java 也是此類應用程序的標準實現。
微服務架構
微服務是可以協同工作並且可以自主 / 獨立部署的小型業務服務。
來自 Martin Fowlers 微服務文章;
微服務架構風格是一種將單個應用程序開發爲一組小型服務的方法,每個服務都在自己的進程中運行並與輕量級機制(通常是 HTTP 或 gRPC API)進行通信。
因此,我們可以說微服務架構是一種雲原生架構方法,其中應用程序由許多鬆散耦合且可獨立部署的較小組件組成。讓我們描述一些微服務特徵:
-
他們有自己的技術棧,包括數據庫和數據管理模型。
-
通過 REST API、事件流和消息代理相互通信。
-
它們按業務能力組織,用線分隔服務,通常稱爲有界上下文。
-
在接下來的部分中,我們還將看到如何將微服務與有界上下文分離。
微服務特性
微服務是小型的、獨立的、鬆散耦合的。一小組開發人員可以編寫和維護服務。每個服務都是一個單獨的代碼庫,一個小型開發團隊就可以管理它。
這些服務可以獨立部署。團隊可以更新現有服務而無需重建和重新部署整個應用程序。
每個服務負責保存其數據或外部狀態。此功能不同於傳統模型,在傳統模型中,單獨的數據層處理數據持久性。
微服務架構的好處
敏捷性——微服務的基本特徵之一是服務更小且可獨立部署。
小型、專注的團隊——微服務應該足夠小,以供單個功能團隊構建、測試和部署。
可擴展性——微服務可以獨立擴展,因此您可以擴展需要較少資源的子服務,而無需擴展整個應用程序。
微服務架構的挑戰
複雜性——微服務應用程序有許多服務需要協同工作並創造價值。由於有許多服務,因此移動部件比單體應用程序多。
網絡問題和延遲——由於微服務很小並且通過服務間通信進行通信,我們應該管理網絡問題。
數據完整性——每個微服務都有自己的數據持久性。因此,數據一致性可能是一個挑戰。
設計微服務架構
在本節中,我們將逐步設計微服務架構。根據需求逐一迭代架構設計。
設計微服務架構
我們在設計微服務架構時遵循了 Database-per-Services Pattern,併爲每個微服務建立了一個數據庫。微服務是從具有分離的獨立服務的整體應用程序模塊中分解出來的。
所以現在,這些數據庫可以是多語言持久性。也就是說 Product 微服務可以使用 NoSQL 文檔數據庫,Shopping Cart 微服務可以使用 NoSQL 鍵值對數據庫,Order 微服務可以使用 Relational 數據庫,滿足每個微服務的數據存儲需求。
第一次架構演變
讓我們看看微服務架構圖,考慮一下這個架構缺少什麼?這種架構的痛點是什麼?我們如何才能將此體系結構發展爲更好的體系結構,使其具有更高的可擴展性、可用性並能夠容納更多併發請求?
前端和後端緊密耦合
看到前端 UI 元素和微服務通信是直接的,管理所有這些連接點似乎很複雜。現在我們應該關注微服務通信!
微服務通信
更改通信機制是遷移到基於微服務的應用程序時面臨的最大挑戰之一。
從本質上講,微服務是分佈式的;微服務通過網絡級別的服務間通信相互通信。每個微服務都有它的實例和進程。
因此,服務必須使用服務間通信協議(如 HTTP、gRPC 或使用 AMQP 協議的消息代理)進行交互。
由於微服務是獨立開發和部署的服務的複雜結構,我們應該考慮通信類型並將它們管理到設計階段。
微服務通信設計模式——API 網關模式
如果您想設計和構建具有多個客戶端應用程序的複雜的大型基於微服務的應用程序,建議使用 API 網關模式。
該模式提供了一個反向代理來將請求重定向或路由到您的內部微服務端點。API 網關爲客戶端應用程序提供單一端點,並在內部將請求映射到內部微服務。我們應該在客戶端和內部微服務之間使用 API 網關。
API 網關可以處理授權等一般技術問題,因此無需在每個微服務中編寫相同的功能,授權可以使用 API 網關以集中方式處理併發送到內部微服務。
此外,API 網關管理到內部微服務的路由,並可以在對客戶端的一次響應中聚合多個微服務請求。
總之,API 網關將放置在客戶端應用程序和內部微服務之間,充當反向代理並將客戶端請求路由到後端服務。它還提供通用技術問題,如身份驗證、SSL 終止和緩存。
設計 API 網關——微服務通信設計模式
我們將通過添加 API 網關模式來迭代我們的電子商務架構。
您可以看到在單個入口點收集客戶端請求並將請求路由到內部微服務的圖像。
此功能將處理客戶端請求並路由內部微服務,將多個內部微服務聚合到單個客戶端請求中,並執行橫切關注點,如身份驗證和授權、速率限制和節流等。
第二次架構演進
我們會繼續演進我們的架構,但是請看看現在的設計,考慮一下我們如何改進設計?
這裏有多個客戶端應用程序連接到一個 API 網關。我們應該小心這種情況,因爲如果我們在這裏放置一個 API 網關,則可能包含與單點故障相關的風險。
如果這些客戶端應用程序增加或添加更多邏輯到 API 網關中的業務複雜性,那將是一種反模式。因此,我們應該使用前端後端模式 (BFF) 來解決這個問題。
後端模式 BFF — 微服務通信設計模式
前端模式的後端可以根據特定的前端應用程序分離 API 網關。因此,我們有多個前端應用程序使用的後端服務,在它們之間,我們包括用於處理、路由和聚合操作的 API 網關。
但這會造成單點故障。爲了解決這個問題,BFF 開啓了創建多個 API Gateway 的可能性,將客戶端應用按照邊界分組,拆分到不同的 API Gateway 中。
單一且複雜的 API 網關可能存在風險,併成爲我們架構中的瓶頸。較大的系統通常通過按功能(如移動、Web 和桌面)對客戶端類型進行分組來公開多個 API 網關。當您避免爲多個接口定製單個後端時,BFF 模式很有用。
因此,我們應該根據用戶界面創建多個 API 網關。這些 API 網關最符合前端環境的需求,無需擔心影響其他前端應用程序。前端後端模式爲實現多個網關提供了方向。
爲前端模式設計後端 BFF — 微服務通信設計模式
我們將根據前端後端模式 BFF 添加更多 API 網關模式來迭代我們的電子商務架構。
如您所見,我們已將多個 API 網關添加到我們的應用程序中。這些 API 網關最符合前端環境的需求,無需擔心影響其他前端應用程序。前端後端模式提供了實現多個網關的方向。
後端內部微服務之間的服務到服務通信——微服務通信設計模式
好的,我們已經在我們的微服務架構中創建了 API 網關。所有這些同步請求都來自客戶端,並通過 API 網關轉到內部微服務。
但是,如果客戶端請求需要多個內部微服務怎麼辦?我們如何管理內部微服務通信?
在設計微服務應用程序時,我們應該注意後端內部微服務如何相互通信。最佳實踐是儘可能減少服務間通信。
但是,有時,由於客戶要求或請求的操作需要調用多個內部服務,我們無法減少這些內部通信。
例如,查看上面的圖片並考慮這樣的用例:
- 用戶簽出購物車並創建訂單
那麼我們如何實現這個請求呢?這些內部調用爲每個微服務進行耦合;在我們的例子中,購物車、產品和定價微服務相互依賴。
如果其中一個微服務沒有響應,它就不能向客戶端返回數據,所以它不是容錯的。如果增加了微服務的依賴和耦合,就會產生很多問題,我們無法充分發揮微服務架構的潛力。
如果客戶簽出購物車,這將啓動一組操作。因此,如果我們嘗試使用請求 / 響應同步消息傳遞模式來執行這個下訂單用例,它看起來就像這張圖片。
正如我們所見,對於一個客戶端 HTTP 請求,我們有六個同步 HTTP 請求。因此,很明顯,它會增加延遲並對我們系統的性能、可擴展性和可用性產生負面影響。
如果我們有這個用例,如果第 5 步或第 6 步失敗或某些中間服務出現故障會怎樣?即使它們沒有宕機,它也可能很忙,一些服務無法及時得到響應,在那種情況下,高延遲是不可接受的。
那麼,這種需求的解決方案是什麼?
我們可以應用兩種方法來解決這些問題:
-
將微服務通信更改爲與消息代理系統異步;我們將在下一節中看到這一點。
-
使用服務聚合器模式在一個 API 網關中聚合一些查詢操作。
服務聚合器模式——微服務通信設計模式
爲了最小化服務到服務的通信,我們可以應用服務聚合器模式。服務聚合器設計模式接收來自客戶端或 API 網關的請求,將請求分派給多個內部後端微服務,然後組合結果並在一個響應結構中響應初始請求者。
服務聚合器模式
通過服務聚合器模式的實現,我們可以減少客戶端和微服務之間的聊天和通信開銷。
設計——服務聚合器模式——服務註冊模式——微服務通信設計模式
本節將通過添加服務聚合器模式 - 服務註冊模式 - 微服務通信設計模式來迭代我們的電子商務架構。
聚合器和服務註冊模式
如您所見,我們已經爲我們的電子商務架構應用了服務聚合器模式——服務註冊模式。
微服務異步基於消息的通信
如果您的通信僅在幾個微服務之間進行,則同步通信是合適的。但是當涉及到多個微服務需要相互調用並且可能要等待很長時間或複雜的操作直到它們完成時,我們應該使用異步通信。
微服務異步通信
否則,微服務的依賴和耦合會造成瓶頸和嚴重的架構問題。
如果你有多個需要相互交互的微服務,並且如果你想在沒有任何依賴或鬆散耦合的情況下與它們交互,那麼我們應該在我們的微服務架構中使用基於異步消息的通信。
因爲基於異步消息的通信與事件一起工作,所以事件可以是微服務之間的一種通信形式。我們稱這種通信爲事件驅動通信。
發佈 - 訂閱設計模式
發佈 - 訂閱是一種消息傳遞模式,它有一個消息發送者(稱爲發佈者)和特定的接收者(稱爲訂閱者)。
發佈 - 訂閱設計模式
因此,發佈者不會直接向訂閱者發送消息。相反,每個服務都在不知道有哪些訂閱者的情況下將消息分類併發布到消息代理系統中。
類似地,訂閱者表達興趣並且只接收他們感興趣的消息而不知道哪些發佈者發送給他們。
設計——發佈 / 訂閱消息代理——微服務異步通信設計模式
在本節中,我們將通過添加用於提供微服務異步通信設計的發佈 - 訂閱消息代理來迭代我們的電子商務架構。
如您所見,我們應用了發佈 - 訂閱消息代理——微服務異步通信設計模式。
如果我們調整我們的技術堆棧,我們可以開始考慮哪些選項可用於發佈 - 訂閱消息代理功能。您可以選擇兩個不錯的選擇:
-
卡夫卡
-
兔 MQ
微服務數據管理
在單體架構中,查詢不同的實體是可以接受的,因爲單個數據庫保存數據。跨多個表查詢數據很簡單;任何不需要的數據更改都可以輕鬆回滾。具有嚴格一致性的關係型數據庫具有 ACID(原子性、一致性、隔離性和持久性)事務保證,因此易於管理和查詢數據。
但在微服務架構中,我們通常使用多語言持久化。這意味着每個微服務都有不同的存儲庫,包括關係數據庫和 NoSQL 數據庫。在執行用戶交互時,我們應該設置一個策略來管理這些數據。
因此,這意味着我們在處理微服務之間的數據交互時有多種模式和實踐;我們將在本節中學習這些模式和原則。
微服務是獨立的,只執行特定的功能需求。在我們的例子中,電子商務應用程序具有產品、購物籃、折扣和訂購微服務。這些微服務需要相互交互以執行我們的客戶用例。
因此,這意味着它們需要經常相互集成。主要是,這些集成正在查詢彼此服務的數據以進行聚合或執行邏輯。
CQRS 設計模式
CQRS 是微服務之間查詢時的關鍵模式之一。我們可以使用 CQRS 設計模式來避免複雜的查詢並消除低效的連接。CQRS 代表命令和查詢責任分離。此模式將數據庫的讀取和更新操作分開。
要隔離命令和查詢,最好將讀寫數據庫分成兩個數據庫。這樣,如果我們的應用程序是讀密集型的,這意味着讀多於寫,我們可以定義一個針對查詢優化的自定義數據模式。
CQRS 設計模式
物化視圖模式是實現讀取數據庫的一個很好的例子。因爲通過這種方式,我們可以避免複雜的連接和映射與預定義的細粒度數據進行查詢操作。
通過這種隔離,我們甚至可以使用不同的數據庫來讀取和寫入數據庫,例如 NoSQL 文檔數據庫來讀取和使用關係數據庫來進行 CRUD 操作。
事件溯源模式
我們學習了 CQRS 模式,CQRS 模式主要和 Event Sourcing 模式一起使用。將 CQRS 與事件溯源模式一起使用時,主要思想是將事件存儲在寫入數據庫中,這將是真實事件數據庫的來源。
之後,CQRS 設計模式的讀取數據庫使用非規範化表提供數據的物化視圖。當然,這些物化視圖讀數據庫從寫數據庫中消費事件並將它們轉換爲非規範化視圖。
事件溯源模式
應用事件溯源模式是將數據保存操作更改爲數據庫。事件溯源模式不是在數據庫中保留最新的數據狀態,而是按照數據事件的順序保存數據庫中的所有事件。該事件數據庫稱爲事件存儲。
它不是更新數據記錄的狀態,而是將每個更改附加到事件的順序列表中。因此,事件存儲成爲數據的真實來源。之後,這些事件存儲轉換爲讀取數據庫。這種轉換操作可以通過事件後消息代理系統的發佈 / 訂閱模式來處理。
設計架構——CQRS、事件溯源、最終一致性、物化視圖
我們將通過應用 CQRS、事件溯源、最終一致性和物化視圖來設計我們的電子商務架構。
CQRS、事件溯源和最終一致性
因此,當用戶創建或更新訂單時,我將使用關係數據庫。當用戶查詢單個訂單或訂單歷史時,我將使用 NoSQL 讀取數據庫並在使用具有發佈 / 訂閱模式的消息代理系統同步兩個數據庫時使它們保持一致。
現在我們必須考慮這些數據庫的技術堆棧;讓我們假設使用 Microsoft SQL Server 作爲寫入操作的關係數據庫,使用 Cassandra 作爲讀取操作的 NoSQL 數據庫。當然,我們將使用 Kafka 將這兩個數據庫與發佈 / 訂閱 Kafka 主題交換同步。
如您所見,我們已經完成了微服務數據庫模式的設計。讓我們深入研究微服務中的這些事件驅動架構。
事件驅動的微服務架構
事件驅動的微服務架構意味着通過事件消息與微服務進行通信。我們在微服務異步通信部分看到了發佈 / 訂閱模式和 Kafka 作爲消息代理系統。
我們說我們可以使用事件驅動架構來實現異步行爲和松耦合結構。例如,服務通過事件消費數據,而不是在需要數據時發送請求。此功能將提供性能提升。
事件中心
而且,事件驅動的微服務架構中也有許多創新,例如使用實時消息傳遞平臺、流處理、事件中心、實時處理、批處理、數據智能等。
所以,我們可以通過演進這個架構,讓這個事件驅動的方法更加通用和實時的事件處理特性。
根據這種新的事件驅動的微服務架構,我們可以通過事件中心連接所有東西。我們可以將 Event-Hubs 看作是一個可以提供實時處理的大型事件存儲數據庫。
設計架構——事件驅動的微服務架構
我們將使用事件驅動的微服務架構設計我們的電子商務應用程序。
事件驅動的微服務架構
現在我們可以決定在這個架構中技術堆棧。當然,我們應該選擇 Apache Kafka——作爲事件中心和 Apache Spark,用於實時和近實時的流應用程序,這些應用程序可以轉換或響應數據流。
正如您所看到的,現在我們有了事件驅動的微服務架構的反應式設計。
現在我們可以問同樣的問題;
- 多少個併發請求可以容納我們的設計?
藉助這種最新的事件驅動微服務架構,通過容器和編排器進行部署,可以以低延遲滿足目標併發請求。因爲這種架構是完全鬆散耦合的,並且是爲高擴展性和高可用性而設計的。
正如您所看到的,我們已經使用設計原則和模式的各個方面來設計我們的電子商務微服務架構。現在,您可以準備好通過這些學習來設計您自己的架構,並知道如何在您的設計中使用這些模式工具箱。
來源:
https://www.toutiao.com/article/7177735037516366371/?log_from=dccc7021f13b3_1671504374835
本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源:https://mp.weixin.qq.com/s/E-sNEjF3q4qMW-gfvLSYug