浅析 Dapr 里的云计算设计模式
Dapr 實際上是把分布式系統 與微服務架構實踐的挑戰以及k8s 這三個主題的全方位的設計組合,特別是Kubernetes設計模式?一書作者Bilgin Ibryam?提出的Multi-Runtime Microservices Architecture,中譯參見敖小劍的博客:?[譯] 多運行時微服務架構。
分布式系統 和微服務架構實踐的核心問題就是要解決系統復雜性這個難題,降低復雜性的通常做法就是分而治之,Dapr的最核心的設計就是Sidecar Pattern?+?Building Block,如下圖:
圖片來源:https://docs.microsoft.com/zh-cn/dotnet/architecture/dapr-for-net-developers/dapr-at-20000-feet
Sidecar Pattern: 通過職責分離與容器的隔離特性,降低應用程式的復雜度。
Building Block:? 類似于樂高搭積木方法,通過Dapr 提供的核心組件(Component),分離與抽象化系統架構。
Dapr 設計上幾乎和Bilgin Ibryam?提出的Multi-Runtime Microservices Architecture?不謀而合,它有幾個核心的設計點:
Sidecar
Building Block & Component
Service Invocation
Middleware
State
基于上面的這些核心設計,Dapr 有了多運行時微服務架構 的特性,以此延伸出底下的重要功能,或者說設計模式:
Security
Observability: tracing, metrics, logs and health
Pub / Sub / Batch Process
Actors
Secret Management
Config Management 正在開發中……
Sidecar
Sidecar是非常重要的云計算設計模式,下面這張圖是 Sidecar 與Microservice 之間搭配后形成多個服務的關系圖,這樣的結構形成了服務網格的概念, Dapr 通過配置的方式,動態生成Sidecar?,隨后伴隨著App,一組Dapr Sidecar + App 的組合稱為Dapr App
Dapr App 在K8s 里面的形態就是 Pod = (App_Container + Sidecar_Container)
同樣的概念,如果Dapr App跑在k8s外面,也就是自承載模式。在自承載模式下,微服務和 Dapr sidecar 在沒有容器業務流程協調程序(如 Kubernetes)的單獨本地進程中運行。
每個Dapr App 都通過Sidecar 溝通,在通信之前,Dapr App 要知道的是對方在哪?所以服務發現和服務調用是Dapr App 要解決的第一個問題,知道彼此在哪了,然后就是通信模式,Dapr 支持HTTP / gRPC 兩種通信模式。Dapr App 之間的默認的通信模式使用gRPC,也就是如果使用HTTP調用Dapr API,內部服務之間的通信也會轉成gRPC。
gRPC 是一種新式的高性能框架,它通過?RPC?(遠程過程調用) 改進。gRPC 使用 HTTP/2 作為傳輸協議,該協議通過 HTTP RESTFul 服務提供顯著的性能增強,包括:
對通過同一連接發送多個并行請求的多路復用支持 - HTTP 1.1 將處理限制為一次處理一個請求/響應消息。
雙向全雙工通信,用于同時發送客戶端請求和服務器響應。
內置流式處理,支持對大型數據集進行異步流式處理的請求和響應。
若要了解有關詳細信息,請查看適用于 Azure 電子書的.NET Cloud-Native中的?gRPC概述。
Dapr Sidecar 有了服務調用、服務發現和通信模式之后,定義出來了一個Building Block (構建塊)的概念,使用聲明的方式,定義多個組件Component 擴展Sidecar的能力,這些能力正是分布式系統需要面對的問題。
構建塊 和 組件
構建基塊封裝分布式基礎結構功能。可以通過 HTTP 或 gRPC API 訪問該功能,目前版本有如下構建塊。
Buiding Block 是每個 Dapr Sidecar 可以擴展的概念,每個 Block 由多個 Components 組成,開發者可以自行設計、擴展 Component,然后貢獻給社區,這里集中了社區貢獻的組件?https://github.com/dapr/components-contrib。我們來看一下微軟的.NET團隊基于Dapr 設計的eshopondapr,圖中每個Dapr標示都是一個Component ,一共標記了六種:
基于這樣的設計,Dapr 把最核心的Component 提供了基于分布式系統的?最佳實踐 (Best Practice)和 設計模式(Design Patterns)
Input/Output Bindings:
全部列表:Supported external bindings
Pub / Sub:
全部列表:Supported pub/sub brokers?Middleware: Dapr 的一種特殊 Components,后面介紹。
Service discovery name resolution: Dapr 的特殊 Components,后面介紹。
State Stores
全部列表:Supported state stores
Secret Stores
全部列表:Supported secret stores
這些核心的設計可以通過代碼倉庫了解:
倉庫?https://github.com/dapr/components-contrib?是Dapr 官方開放的Component ,開發者可以通過 PR 提交來把 擴展的Component 貢獻給社區,目前已經有70 多個Components 可以使用,使用的時候要注意版本的階段性是在Alpha / Beta / GA,一定要做好風險評估。
服務調用和服務發現
這就是我們在微服務里面常說的服務治理,Dapr 作為一個分布式系統,多個Dapr app怎么知道彼此的存在,通過什么方式進行溝通,這就是Dapr的服務治理要解決的問題,Dapr的服務發現機制,按照架構的不同方式(k8s還是自托管)有不同的實現,官方文檔(https://docs.dapr.io/zh-hans/developing-applications/building-blocks/service-invocation/service-invocation-overview/)里的這張圖介紹了調用邏輯
服務 A 對服務 B 發起HTTP/gRPC的調用。
Dapr 使用?name resolution component?發現 Service B’s 位置 取決于運行的環境?hosting platform.
Dapr 將消息轉發至服務 B的 Dapr 邊車
注: Dapr 邊車之間的所有調用考慮到性能都優先使用 gRPC。僅服務與 Dapr 邊車之間的調用可以是 HTTP 或 gRPC
?
服務 B的 Dapr 邊車將請求轉發至服務 B 上的特定端點 (或方法) 。服務 B 隨后運行其業務邏輯代碼。
服務 B 發送響應給服務 A。響應將轉至服務 B 的邊車。
Dapr 將消息轉發至服務 A 的 Dapr 邊車。
服務 A 接收響應。
Dapr 命名有Namespace 概念,基本格式為FQDN
Dapr 的Service Invocation 支持 gRPC / HTTP 兩種方式,默認的 Service to Service 使用gRPC 通信。
Service to Service 使用mTLS 做傳輸層加密
支持 Service 的ACL,可以個別控制每個API 與Method 的操作
支持 Retry 機制
可以使用其他service discovery 實現
RR load balancing with mDNS
支持tracing 和 metric
問題空間涉及并發性。如果沒有Actor,則需要在代碼中引入顯式鎖定機制。
可以將問題空間分區為小、獨立和隔離的狀態和邏輯單元。
不需要低延遲的讀取Actor 狀態。? 因為Actor 操作是按順序執行,不能保證低延遲讀取。
不需要在一組Actor 之間查詢狀態。跨Actor 的查詢效率低下,因為每個Actor 的狀態都需要單獨讀取,并且可能會導致不可預測的延遲。
服務治理:包含Service Invocation、Service Trusted and Authorization (服務的信任、認證與授權)、通信模式(HTTP / gRPC)、通信機制(Push / Pull)、狀態管理(State Machine)
運維:高可用、擴展機制、Log 處理、分布式追蹤、Metric
安全性:Data Encryption、Secret Management、KMS、Auth 集成
性能和可靠性:Rate Limit、降級、熔斷…
可擴展的架構
如何提升開發團隊的效能
這里面有很多核心的概念:
Middleware
和ASP.NET Core 支持通過 middleware 處理 HTTP request / response 完成一些 Cross-Cutting (AoP) 的功能,Dapr 也支持 Middleware 的概念,如下圖:
Dapr 允許通過鏈接一系列中間件組件來定義自定義處理管道。請求在路由到用戶代碼之前經過所有已定義的中間件組件,然后在返回到客戶機之前,按相反順序經過已定義的中間件,如下圖中所示。
Actors
Actor 模型 起源于Carl Hewitt ?在 1973 年提出的作為并發計算的概念模型,這種形式的計算會同時執行多個計算。當時并沒有高度并行的計算機,但多核 Cpu 和分布式系統的最新進步使得Actor 模型 變得流行。在Actor 模型中,Actor 是一個計算和狀態獨立的單元。Actors 完全彼此隔離,它們永遠不會共享內存。Actors 使用消息相互通信。當一個Actor 收到消息時,它可以更改其內部狀態,并將消息發送到其他 (可能是新的) Actors。
Actor模型使得編寫并發系統變得更簡單的,它提供了基于 turn-based 的 (或單線程) 訪問模型。多個Actors可以同時運行,但每個Actor 一次只處理一個接收的消息。這意味著,在任何時候,都可以確保在Actors 中最多有一個線程處于活動狀態。這使得編寫正確的并發系統和并行系統變得更加容易。
Dapr 的實現基于?項目 "Orleans" 中引入的虛擬Actor模式。對于虛擬Actor模式,不需要顯式的創建Actor。第一次將消息發送到Actor時,Actor將被隱式激活并放置在群集中的節點上。當不執行操作時,Actor 會以靜默方式從內存中卸載。如果某個節點出現故障,Dapr 會自動將激活的Actor 移到正常的節點。除了在Actor之間發送消息以外,Dapr Actor模型還支持使用計時器和提醒調度將來的工作。
雖然Actor模型 提供了很大的優勢,但必須仔細考慮Actor的設計。例如,如果多個客戶端調用相同的Actor,則會導致性能不佳,因為Actor ?操作會按順序執行。下面的檢查清單是是否適用于 Dapr Actor的一些標準:
滿足這些條件的一種設計模式非常好,就是?基于業務流程的 saga?或?流程管理器?設計模式。Saga 管理必須執行的一系列步驟才能達到某些結果。Saga (或進程管理器) 維護序列的當前狀態,并觸發下一步。如果一個步驟失敗,saga 可以執行補償操作。利用Actor,可以輕松處理 saga 中的并發,并跟蹤當前狀態。?EShopOnDapr 參考應用程序使用 saga 模式和 Dapr Actor來實現排序過程。
為了提供可伸縮性和可靠性,將在Actor服務的所有實例中對actor進行分區。Dapr placement ?服務負責跟蹤分區信息。啟動Actor 服務的新實例時,Sidecar 會將支持的Actor 類型注冊到placement 服務。placement 服務計算給定Actor 類型的更新分區信息,并將其廣播給所有實例。
總結
分布式架構的門檻比較高,需要考慮的問題很多,通常我們都需要考慮如下問題。
上述的這些東西,通常是一個有經驗的、資深的軟件工程師,如何在資源有限的情況下,可以快速開發、容易測試,是很多技術人的痛點所在。
這些問題從個別來看,都有相當成熟的系統,如果個別看,有很多現成的實踐可以參考。但是對于存在了幾十年的祖傳代碼的系統架構而言,如果要進行微服務改造,往往都要傷筋動骨,讓技術主管和架構師傷透腦筋,往往要面對新舊技術的整合,同時也要面對現實的團隊需求的交互和對于新技術的學習門檻。對于開發應用程式的開發人員來講,滿足業務需求的開發已經夠頭痛了,還要考慮這么多系統架構層面的東西,這種事是無法靠熱情填補的。Dapr 將一些經過驗證的技術和最佳實踐帶到微服務開發中。它通過即插即用模型將90 年代的數據驅動的客戶端/服務器應用程序的操作,應用于現代云原生應用程序所需的最常見服務,讓我們集中于業務需求的開發,而不需要考慮系統架構層面的東西 。
Dapr 正式發布已經過去了半年時間了,現在最新版本是1.3.0.? 下圖是技術采用生命周期,在早期采用者和早期大眾的中間,有一個死亡之井,無法越過死亡之井,則死亡,Dapr已經跨過了死亡之井,你可以采用Dapr了。
總結
以上是生活随笔為你收集整理的浅析 Dapr 里的云计算设计模式的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 使用 baget 搭建 nuget 私有
- 下一篇: .NET 6 中哈希算法的简化用法