Dapr 在阿里雲原生的實踐

什麼是 Service Mesh?

從 2010 年的時候,SOA 架構就已經在中大型互聯網公司中開始流行,阿里也在 2012 年開源了 Dubbo 。而之後微服務架構開始流行,大量互聯網和傳統企業都投身到微服務的建設中。在國內逐漸形成了 Dubbo 和 Spring Cloud 兩大微服務陣營。在 2016 年的時候,微服務領域一個更具有前沿性,更加符合容器和 Kubernetes 的微服務方案正在孕育,這個技術被稱爲 Service Mesh。時至今日,Service Mesh 理念已經得到了大範圍普及,很多公司都在 Service Mesh 領域有了落地。

Service Mesh 定義

Service Mesh 是一個基礎設施層,主要圍繞服務間通信來進行。現在的雲原生應用的服務拓撲結構非常複雜,Service Mesh 可以在這種複雜拓撲結構中實現可靠的請求傳送。Service Mesh 是以 Sidecar 的方式運行,應用旁邊會運行一個獨立的 Service Mesh 進程,Service Mesh 負責遠程服務的通信。軍用三輪摩托車和 Service Mesh 非常相像,軍用三輪摩托車上一個士兵負責開車,一個士兵負責對人發起射擊。

Service Mesh 解決的痛點

傳統的微服務架構大都以 RPC 通信框架爲基礎,在 RPC SDK 中提供了服務註冊 / 發現,服務路由,負載均衡,全鏈路跟蹤等能力。應用業務邏輯和 RPC SDK 在同一個進程中,這種方式給傳統微服務架構帶了很多挑戰:中間件能力相關代碼侵入到了業務代碼中,耦合性很高;推動 RPC SDK 的升級成本非常高,進而也導致了 SDK 版本分化非常嚴重。同時這種方式對應用開發者的要求比較高,需要有豐富的服務治理的運維能力,有中間件的背景知識,使用中間件的門檻偏高。

通過 Service Mesh 方式將一些 RPC 的能力進行下沉,這樣可以很好的實現關注點分離、職責邊界的明確。隨着容器和 Kubernetes 技術的發展,Service Mesh 已經成爲雲原生的基礎設施。

Istio 介紹

在 Service Mesh 領域中, Istio 毫無疑問是當中的王者。Istio 由控制面和數據面構成,在 ServiceMesh 中,不同的 Service 之間,通過 Proxy Sidecar 進行通信。Istio 最核心功能是流量管理,通過數據面和控制面協調完成。Istio 是由 Google 聯合 IBM,Lyft 一起發起的,是 CNCF 生態版圖 Service Mesh 領域的最純正血統,有望成爲 Service Mesh 事實標準。

Istio 的數據面默認使用 Envoy,Envoy 是社區裏默認的最佳數據面。Istio 數據面和控制面的交互協議是 xDS。

Service Mesh 小結

最後,對 Service Mesh 做下小結:

什麼是 Dapr?

Service Mesh 遇到的挑戰

用戶在雲上部署業務的形態主要有普通應用類型和 FaaS 類型。Faas 場景下,比較吸引用戶的是成本和研發效率,成本主要通過按需分配和極致的彈性效率來達成。而應用開發者期望通過 FaaS 提供多語言的編程環境,提升研發效率,包括啓動時間、發佈時間、開發的效率。

Service Mesh 的實現,本質是原協議轉發,原協議轉發可以給應用帶來零侵入的優勢。但是原協議轉發也帶來了一些問題,應用側中間件 SDK 還需要去實現序列化和編解碼工作,所以在多語言實現方面還有一定成本;隨着開源技術的不斷髮展,使用的技術也在不斷迭代,如果想從 Spring Cloud 遷移到 Dubbo ,要麼應用開發者需要切換依賴的 SDK,如果想借助 Service Mesh 來達到這個效果,Service Mesh 需要進行協議轉換,成本較高。

Service Mesh 更加聚焦於服務間的通訊,而對其他形態的 Mesh 的支持上非常少。比如 Envoy, 除了在 RPC 領域比較成功外,在 Redis、消息等領域的嘗試都未見成效。螞蟻的 Mosn 中支持了 RPC 和消息的集成。整體多 Mesh 形態的需求是存在的,但是各個 Mesh 產品各自發展,缺少抽象和標準。如此多形態的 Mesh ,是共用一個進程嗎?如果是共用一個進程,那麼是共用一個端口嗎?許多問題都沒有答案。而控制面方面,從功能角度來看的話,大都圍繞流量來展開。看過 xDS 協議裏的內容,核心是圍繞發現服務和路由來展開。其他類型的分佈式能力,在 Service Mesh 的控制面中基本沒有涉及,更談不上抽象各種類似 xDS 的協議去支持這些分佈式能力。

因爲成本和研發效率等原因,FaaS 受到了越來越多客戶的選擇,FaaS 對多語言和編程 API 的友好性上有了更多訴求,那麼 Service Mesh 在這兩塊還是不能給客戶帶來額外的的價值。

分佈式應用的需求

Bilgin Ibryam 是 Kubernetes Patterns 的作者,是 RedHat 的首席中間件架構師,在 Apache 社區裏非常活躍。他發表了一篇文章對當前分佈式的一些困難和問題進行了抽象,將分佈式應用需求分成了 4 個大種類:生命週期、網絡、狀態、綁定。每種類型下面還有一些子能力,如 Point-to-Point, pub/sub, Caching 等比較經典的中間件能力。應用對分佈式能力有如此多的需求,而 Service Mesh 顯然不能滿足應用的當前的需求。Biligin Ibryam 還在文章中提出了 Multiple Runtime 的理念來解決 Service Mesh 的困境。

Multiple Runtime 理念推導

在傳統的中間件模式下,應用和分佈式能力是在一個進程中,以 SDK 方式進行集成。隨着各種基礎設施下沉,各種分佈式能力從應用中移到了應用外。如 K8s 負責了生命週期相關的需求,Istio、Knative 等都負責一些分佈式能力。如果將這些能力都移動到獨立的 Runtime 中,那麼這種情況無論從運維層面還是資源層面來看,都是沒辦法接受的。所以這時候肯定需要將部分 Runtime 進行整合,最理想的方式肯定是整合成一個。這種方式被定義成 Mecha ,中文意思是機甲的意思,就像日本動漫裏主人公變身穿上機甲,機甲的每個部件就像一個分佈式能力,機甲裏的人對應的是主應用,也叫 Micrologic Runtime 。 這兩個 Runtime 可以是一對一的 Sidecar 方式,這種非常適合傳統的應用;也可以是多對一的 Node 模式,適合邊緣場景或者網管模式下。

那麼對於將各種分佈式能力進行整合的 Mecha Runtime 這一目標本身問題不大,那麼怎麼整合呢?對 Mecha 有什麼要求呢?

  1. Mecha 的組件能力是抽象的,任何一個開源產品可以快速進行擴展和集成。

  2. Mecha 需要有一定的可配置能力,可以通過 yaml/json 進行配置和激活。這些文件格式最好能和主流的雲原生方式對齊。

  3. Mecha 提供標準的 API ,和主應用之間的交互的網絡通信基於此 API 來完成,不再是原協議轉發,這樣對於組件擴展和 SDK 的維護都能帶來極大的便利性。

  4. 分佈式能力中的生命週期,可以將部分能力交接過底層的基礎設施,比如 K8s。當然有些複雜的場景,可能需要 K8s、APP、Mecha Runtime 一起來完成。

既然最理想只剩下一個 Runtime , 那麼爲什麼還叫 Multiple Runtime 呢?因爲應用本身其實也是一個 Runtime ,再加上 Mecha Runtime ,所以至少是兩個 Runtime 。

Dapr 介紹

前面的 Multiple Runtime 介紹地比較抽象,可以來從 Dapr 來重新理解下 Multiple Runtime 。Dapr 是 Multiple Runtime 的一個很好的踐行者,所以 Dapr 肯定和應用共存的,要麼是 Sidecar 模式,要麼是 Node 模式。Dapr 這個詞其實是不是造出來的,而是 Distributed Application Runtime 的首字母拼接而成,Dapr 這個圖標可以看出來是一個帽子,這個帽子其實是一個服務生的帽子,表示的含義是要爲應用做好服務。

Dapr 是由微軟開源的,阿里巴巴深度參與合作。當前的 Dapr 已經發布 1.1 版本,現在已經接近生產的能力。

既然 Dapr 是 Multiple 的最佳實踐者,那麼 Dapr 的運行機制也是基於 Mulitple Runtime 的理念來構建的。Dapr 對分佈式能力進行了抽象,定義了一套分佈式能力的 API,而且這些 API 是基於 Http 和 gRPC 來構建的,這種抽象和能力在 Dapr 中被稱爲 Building Block;Dapr 爲了支持開源產品和商業化等不同類型的產品對 Dapr 中的分佈式能力進行擴展,內部擁有一套 SPI 擴展機制,這種 SPI 機制叫 Components 。應用開發者在使用 Dapr 之後,只需要針對各種分佈式能力的 API 來進行編程,而無需過多關注具體的實現,而 Dapr 中根據 Yaml 文件可以自由激活對應的組件。

Dapr 特性

應用開發者使用各種多語言的 Dapr SDK 就可以直接擁有各種分佈式能力。當然開發者也可以自己基於 HTTP 和 gRPC 來完成調用。Dapr 可以運行在大部分環境裏,包括你自己電腦的環境,或者任何 Kubernetes 環境下,或者邊緣計算場景,或者阿里雲、AWS、GCP 等雲廠商。

Dapr 社區裏已經集成了 70+ 的 components 實現,應用開發者可以快速進行選擇和使用。相似能力的組件的替換,可以通過 Dapr 裏完成,應用側可以做到無感知。

Dapr 核心模塊

我們從 Dapr 產品模塊緯度來解析下,看爲什麼 Dapr 是 Mulitiple Runtime 的一個很好實踐。

Component 機制確保了可以快速擴展能力的實現,現在社區已經有的 Components 實現已經有 70 個以上,不只包含開源產品,還包含雲上的商業化產品。

Building Block 表示的的分佈式能力,現在只支持 7 個,後續需要更多的分佈式能力能夠進來。BuildingBlock 現在支持了 HTTP 和 gRPC 這兩種開放,而且普及度已經非常高的協議。而 Dapr 中 Building Block 下具體那些 Components  會被激活,需要依賴 YAML 文件來進行。正因爲 Dapr 中採用了 HTTP、gRPC 的方式暴露能力,所以在應用側想要支持多語言的標準的 API 編程界面就變得更爲容易了。

Dapr 核心:Component & Building Block

Dapr Component 是 Dapr 插件擴展的核心,是 Dapr 的 SPI 。現在支持的 Components 有 Bindings 、Pub/Sub、Middleware、ServiceDiscovery、Secret Stores、State。擴展點裏有些是功能緯度的如 Bindings,pub/sub,state 等,有些是橫向的如 Middleware。假設你想實現 Redis 的 Dapr 集成,你只需要去實現 Dapr 的 State Component。Dapr Building Block 是 Dapr 提供出來的能力,支持 gRPC 和 HTTP 方式。現在支持的能力有 Service Invocation,State,Pub/Sub 等。

一個 Building Block 由 1 個或多個 Component 組成,Binding 的 Building Block 包含 Bindings 和 Middleware 兩個 Component 。

Dapr 整體架構

Dapr 和 Istio 一樣,也有數據面和控制面。控制面有 Actor Placement,Sidecar Injector, Sentry, OPerator。Actor Placement 主要爲 Actor 服務,Sentry 做安全和證書相關的工作,Sidecar Injector 主要負責 Dapr Sidecar 的注入。Dapr 裏激活某個組件實現是通過 YAML 文件來完成的,YAML 文件可以通過兩種方式來指定:一種是本地指定運行時參數,另外一種是通過控制平面 Operator 來完成,將組件激活的文件以 K8s CRD 方式存儲並下發到 Dapr 的 Sidecar 中。控制面的 2 個核心組件都依賴於 K8s 來運行。現在的 Dapr Dashboard 功能還很弱,短期還不到增強的方向,現在各個組件的集成之後,各個組件的運維還需要在原來的控制檯裏完成,Dapr 控制平面不參與具體組件實現的運維。

Dapr 標準運行形式是和應用在同一個 Pod 中,但分屬於兩個容器。Dapr 的其他內容,前面已經做了足夠的介紹,這裏不做介紹了。

Dapr 微軟落地場景

Dapr 經歷了 2 年左右的發展,在微軟內部的落地情況是怎麼樣的呢?

Dapr 的 github 上有兩個項目:workflows 和  Azure Functions Dapr extensions。Azure Logic App 是微軟的一個基於雲上的自動工作流平臺。而 Workflows,就是整合了 Azure Logic App 和 Dapr。Azure Logic App 中有幾個關鍵的概念,Trigger 和 Connector 和 Dapr 非常契合。Trigger 可以使用 Dapr 的 Input Binding 來完成,依賴 Dapr 的 Input Binding 的大量組件實現,可以擴大流量入口的類型。而 Connector 和 Dapr 的 Output Binding 或者 Service Invocation 的能力非常匹配,可以快速訪問外部資源。Azure Functions Dapr extensions 則是基於 Azure Function extension 做的 Dapr 支持,可以讓 Azure Function 快速使用上 Dapr 的各種 Building Block 的能力,同時能給函數開發者帶來多語言的相對簡單一致的編程體驗。

Azure API Management Service 和上面提到的兩個落地場景的角度不太一致,它是前提是應用之間已經通過 Dapr Sidecar 方式進行訪問,應用的提供的服務通過 Dapr 來進行暴露。這時候如果非 K8s 的應用或者跨集羣的應用想要訪問當前集羣的服務,就需要一個網關,這個網關可以直接暴露 Dapr 的能力,在網關中會增加一些安全和權限的控制。當前支持 3 種 Building Block:Service Invocation、pub/sub、resource Bindings。

Dapr 小結

Dapr 提供的面向能力的 API ,能夠給開發者帶來支持多語言的一致的編程體驗,同時這些 API 的 SDK 相對比較輕量級。這些特性非常適合 FaaS 場景。而隨着 Dapr 集成生態的不斷完善,開發者面向能力編程的優勢將進一步擴大,通過 Dapr 可以更加方便地將 Dapr 組件的實現進行替換,而無需開發者做代碼的調整。當然原來的組件和新的組件實現,必須是相同類型的分佈式能力。

和 Service Mesh 差異點:

提供能力:Service Mesh 專注服務調用;Dapr 提供的分佈式能力範圍更廣,覆蓋多種分佈式原語。

工作原理:Service Mesh 採用原協議轉發做到零侵入;Dapr 採用多語言 SDK + 標準 API + 各種分佈式能力。

面向領域:Service  Mesh 對傳統微服務的無侵入升級支持很友好;Dapr 對面嚮應用的開發者提供了更加友好的編程體驗。

阿里在 Dapr 上的探索

阿里在 Dapr 的發展路線

2019 年 10 月,微軟開源了 Dapr,發佈了 0.1.0 的版本。這時候,阿里和微軟正好因爲 OAM 已經展開一些合作,瞭解到了 Dapr 這個項目,所以就開始對其進行評估。在 2020 年初的時候,阿里和微軟在阿里巴巴線下做了一輪 Dapr 的溝通,瞭解到了微軟對 Dapr 的看法、投入,以及後續的發展計劃。此時阿里已經認定 Dapr 這個項目具有較大的價值。一直到 2020 年中,纔開始圍繞 Dapr 開始投入工作。到 10 月份,Dapr 在函數計算場景下開始線上灰度部分功能,到今天爲止,函數計算相關的 Dapr 的所有功能的灰度已經基本完成,開始開放公測。到 2021 年 2 月份,終於發佈了 1.0 版本。

阿里雲函數計算集成 Dapr

除了極致彈性等運維側的好處之外,函數計算區別於中臺應用的地方還在於,函數計算更加關注能夠給開發者帶來更好的研發體驗,提升整體的研發效率。而 Dapr 能夠給函數計算的價值就是提供多語言的統一的面向能力的編程界面,而開發者無需關注具體的產品。像 Java 語言如果要使用阿里雲上的 OSS 服務,需要引入 maven 依賴,同時需要寫一些 OSS 代碼,而通過 Dapr 你只需要調用 Dapr SDK 的 Binding 方法即可以做到,方便編程的同時,整個可運行包也無需引入多餘的依賴包,而是可控的。

函數計算英文名是 Function Compute,簡稱爲 FC。FC 的架構包含的系統比較多,和開發者相關的主要包括 Function Compute Gateway 和函數運行的環境。FC Gateway 主要負責承接流量,同時會根據承接的流量的大小,當前的 CPU、內存使用情況,對當前函數實例進行擴縮容。函數計算運行時環境部署在一個 Pod 中,函數實例在主容器中,dapr 則是在 sidecar 容器中。當有外部流量訪問函數計算的服務時,流量會先走到 Gateway ,Gateway 會根據訪問的內容將流量轉發到提供當前服務的函數實例中,函數實例接收到請求之後如果需要訪問外部資源,就可以通過 Dapr 的多語言 SDK 來發起調用。這時候 SDK 會向 Dapr 實例發起 gRPC 請求,而在 dapr 實例中回根據請求的類型和 body 體,選擇對應的能力和組件實現,進而向外部資源發起調用。

在 Service Mesh 場景下,Mesh 以 Sidecar 形式存在,和應用部署在同一個 Pod 的兩個容器裏,可以很好滿足 Service Mesh 的需求。但是在函數計算場景下,Dapr 作爲獨立容器方式運行過於消耗資源,而且多個函數實例本身部署在一個 Pod 中以便節省資源開支和秒級彈性。所以在函數計算場景下,需要將函數實例和 Dapr 進程部署在同一個容器下,但是以兩個進程方式存在。

函數計算場景下,可以設置預留實例數,表示當前函數最小實例數。如果有預留的實例,但是這些實例長久沒有流量訪問需要進入暫停 / 休眠狀態,這種方式和 AWS 的方式是一致的。進入休眠狀態的函數,實例內的進程或者線程需要停止運行。函數運行時中增加了 Extension 結構,來支持 Dapr 生命週期的調度。當函數實例進入休眠狀態時,extension 通知 Dapr 進入休眠狀態;當函數實例恢復運行之後,extension 通知 Dapr 重新恢復之前運行的狀態。Dapr 內部的組件實現需要能支持這種方式的生命週期管理,以 Dubbo 爲例,Dubbo 的註冊中心 nacos 需要定時往 Nacos server 發送心跳保持瞭解,同時 Dapr 集成的 Dubbo Consumer 也需要往 Dubbo Provider 發送心跳。當進入暫態之後,心跳都需要退出;當恢復運行之後,整個運行狀態需要恢復。

上面講到的函數計算和 Dapr 結合的點,都是基於對外的流量,那麼流入的流量呢?消息的流量是否可以直接流入到 Dapr ,而無需經過 Gateway 呢?要做到這一點,還需要在 Dapr Sidecar 將一些性能數據及時上報給 Gateway ,方便 Gateway 可以做到資源的彈性。

SasS 業務上雲

隨着阿里內部孵化的 SaaS 業務越來越多,SaaS 業務對外服務的訴求非常強烈。而 SaaS 業務對多雲部署的訴求非常強烈,客戶期望 SaaS 業務能部署在阿里雲公有云或者華爲專有云上。而且客戶期望底層依賴的技術是開源的或者標準的雲廠商的商業化產品。

以阿里一個 SaaS 業務上雲來說明,左側是阿里內部原來的系統,右側是改造之後的系統,改造的目標是將依賴的阿里內部的系統切換成開源軟件,Ali RPC 切換到 Dubbo,而阿里內部的 Cache,Message,Config 分別切換到 Redis、RocketMq 和 Nacos。期望通過 Dapr 來實現最小代價的切換。

既然想用 Dapr 來完成這個使命,那麼最簡單粗暴的方法肯定是讓應用依賴 Dapr 的 SDK,但是這種方式改造成本太高,所以我們在保持原來 API 不變的情況下,將底層實現適配到 Dapr SDK。通過這種方式,應用就可以直接使用原來的 API 訪問 Dapr,只需要升級對應的依賴 JAR 包版本。改造之後,開發者還是面向原來的 SDK 進行編程,但是底層已經被替換成了 Dapr 的面向能力編程,所以在遷移過程中,應用可以使用一套代碼,而無需爲每個雲環境或者不同技術維護不同的分支。集團內部用 Dapr Sidecar 的時候,會使用 rpc.yaml、cache.yaml、msg.yaml、config.yaml 來激活組件實現,而在公有云上回通過 dubbo.yaml、redis.yaml、rocketmq.yaml、nacos.yaml 文件來激活適合阿里雲環境的組件實現。這種通過不同 yaml 文件激活不同組件來屏蔽組件實現的方式給 SaaS 業務多雲部署形態帶來了極大的便利。

釘釘是 Dapr 的重要合作伙伴和推動者,和雲原生團隊合作推進 Dapr 在釘釘落地。通過將一些中間件能力下沉到 Dapr Sidecar 之後,屏蔽了底層相似能力的中間件實現。但是釘釘還有自己的業務痛點,釘釘通用的業務組件是強業務綁定,需要具體的業務進行一些定製,這樣同時導致了複用度很低,所以釘釘期望通過將部分業務組件能力下沉到 Dapr。這樣可以讓不同業務有相同的編程體驗,而組件維護者只需要維護好 Components 實現。

Dapr 展望

基礎設施下沉成爲軟件發展趨勢

軟件架構的發展歷史及其精彩。回顧阿里巴巴系統架構演進的歷史,能讓人瞭解國內甚至全球的軟件架構的發展歷史。淘寶最開始成立的時候,是單體應用;隨着業務規模的發展,系統首先對硬件進行升級這種 Scale Up 的方式;但是很快發現這種方式遇到了各種各樣的問題,所以在 2008 年開始引入了微服務的解決方案;SOA 的解決方案是分佈式的,對於穩定性,可觀測性等方面,需要引入熔斷、隔離、全鏈路監控等高可用方案;接下來面臨的問題是怎麼在機房、IDC 層面來讓業務達到 99.99% 以上可用的 SLA,這時候就有了同城雙機房、異地多活等解決方案。而隨着雲技術的不斷髮展,阿里巴巴擁抱和引導雲原生技術的發展,積極擁抱雲原生技術,以 K8s 爲基礎,積極開展雲原生技術的升級。

從這個歷史中,我們可以發現,軟件架構新的訴求越來越多,原先底層基礎設施無法完成只能交給應用側富 SDK 去完成,在 K8s 和容器逐漸成爲標準之後,重新將微服務和一些分佈式能力還給基礎設施。未來的趨勢是以 Service Mesh 和 Dapr 爲代表的分佈式能力下沉,釋放雲和雲原生技術發展的紅利。

雲原生場景下的應用開發者的訴求

未來的應用開發者,應該期望能夠面向能力,無言無關,不和具體雲廠商和技術綁定的開發體驗,同時通過雲技術的紅利能夠做到極致的彈性帶來的成本優勢。我相信這個理想還是有可能實現的一天的,從當前的角度出發,怎麼樣才能完成這個目標呢?

  1. Multiple Runtime 理念能夠真正落地,並且能夠持續發展;

  2. 以 Dapr 爲例,期望能將 Dapr 面向分佈式能力的 API 推動成爲一個行業標準,並且這個標準是需要持續發展的;

  3. K8s 和 Serverless 技術的持續發展,未來可以將彈性做到極致。

Dapr 社區方向

最後來看下 Dapr 的社區發展:

  1. 推動 API 標準化,集成更多分佈式能力;
  2. 更多 Component 集成,Dapr 生態完善;
  3. 更多公司落地,拓展產品邊界和打磨 Dapr 產品, 達到生產可用;
  4. 進入 CNCF, 成員雲原生的 Multiple Runtime 的事實標準。
本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源https://mp.weixin.qq.com/s/6t7BGz_rC4N-n-DPxcnuhQ