內容摘要:Service Mesh 落地實踐三年,效果一直並不理想,到了該反思的時候了。Mecha 作為面向服務的分佈式能力抽象層,是 Service Mesh 模式的自然進化版本,預計也將是雲原生化和 Mesh 化的必然趨勢,讓我們將 Mesh 進行到底。
Mecha 介紹
什麼是 Macha?
Mecha 一詞,相信愛好動漫的同學應該都不陌生。是的,就是大家熟悉的那個 Mecha(機甲):
Mecha 這個詞之所以出現在這裡,主要是因為 Bilgin Ibryam 的這個博客文章 “Multi-Runtime Microservices Architecture”,提出了微服務架構的一個新的設想:Multiple Runtime。
備註:這篇博客文章強烈推薦閱讀,我甚至建議在閱讀本文之前先閱讀這篇文章,因為我今天的內容,可以視為對這個文章的深度解讀和思考。為了方便,這裡提供一份中文翻譯版本 多運行時微服務架構。
在這篇博客中,Bilgin Ibryam 首先分析並總結了分佈式應用的四大需求:
- 生命週期(Lifecycle)
- 網絡(Networking)
- 狀態(State)
- 捆綁(Binding)
由於每種需求存在的問題和侷限性,導致傳統解決方案如企業服務總線(ESB)及其變體(例如面向消息的中間件,更輕量級的集成框架等)不再適用。隨著微服務架構的發展,以及容器和 Kubernetes 的普及和廣泛使用,雲原生思想開始影響這些需求的實現方式。未來的架構趨勢是通過將所有傳統的中間件功能移至其他運行時來全面發展,最後的目標是在服務中只需編寫業務邏輯。
備註:詳情請見原文,為了節約篇幅,這裡只做簡單概述,不完全引用原文內容。
下圖是傳統中間件平臺和雲原生平臺的對比,傳統中間件以各種SDK的方式提供能力,而云原生平臺則通過各種外圍Runtime(典型如大家熟悉的Servicemesh/Istio):
因此作者引入了 Multiple Runtime 的概念:
作者提出:很可能在將來,我們最終將使用多個運行時來實現分佈式系統。多個運行時,不是因為有多個微服務,而是因為每個微服務都將由多個運行時組成,最有可能是兩個運行時-自定義業務邏輯運行時和分佈式原語運行時。
對多運行時微服務架構和 Mecha 的說明:
您還記得電影《阿凡達》和科學家們製作的用於去野外探索潘多拉的 Amplified Mobility Platform (AMP)“機車服”嗎?這個多運行時架構類似於這些 Mecha-套裝,為人形駕駛員賦予超能力。在電影中,您要穿上套裝才能獲得力量並獲得破壞性武器。在這個軟件架構中,您將擁有構成應用核心的業務邏輯(稱為微邏輯/micrologic)和提供強大的開箱即用的分佈式原語的 Sidecar Mecha 組件。Micrologic 與 Mecha 功能相結合,形成多運行時微服務,該服務將進程外功能用於其分佈式系統需求。最棒的是,Avatar 2 即將面世,以幫助推廣這種架構。我們最終可以在所有軟件會議上用令人讚歎的機甲圖片代替老式的邊車摩托車;-)。接下來,讓我們看看該軟件架構的詳細信息。
這是一個類似於客戶端-服務器體系結構的雙組件模型,其中每個組件都是獨立的運行時。它與純客戶端-服務器架構的不同之處在於,這兩個組件都位於同一主機上,彼此之間有可靠的網絡連接。這兩個組件的重要性相當,它們可以在任一方向上發起操作並充當客戶端或服務器。其中的一個組件稱為 Micrologic,擁有非常少的業務邏輯,把幾乎所有分佈式系統問題都剝離出去了。另一個伴隨的組件是 Mecha,提供了我們在本文中一直討論的所有分佈式系統功能(生命週期除外,它是平臺功能)。
作者在這裡正式提出了 Mecha 的理念:
思路大體是:Smart Runtime, Dumb Pipes。
我對 Mecha 的理解是:業務邏輯在編碼開始階段應該是“裸奔”的,專注於業務邏輯的實現,而儘量不涉及到底層實現邏輯;而在運行時,則應該裝備“機甲”,全副武裝,大殺四方。熟悉的味道是吧?標準而地道的雲原生思想。
Mecha 的本質
作者在原文中探討了 Mecha 運行時的特性:
- Mecha 是通用的,高度可配置的,可重用的組件,提供分佈式原語作為現成的能力。
- Mecha 可以與單個 Micrologic 組件一起部署(Sidecar 模式),也可以部署為多個共享(注:我稱之為 Node 模式)。
- Mecha 不對 Micrologic 運行時做任何假設,它與使用開放協議和格式(例如 HTTP/gRPC、JSON、Protobuf、CloudEvents)的多語言微服務甚至單體一起使用。
- Mecha 以簡單的文本格式(例如 YAML、JSON)聲明式地配置,指示要啟用的功能以及如何將其綁定到Micrologic 端點。
- 與其依靠多個代理來實現不同的目的(例如網絡代理、緩存代理、綁定代理),不如使用一個 Mecha 提供所有這些能力。
下面是我對上述特性的個人理解:
- Mecha 提供的是能力,以分佈式原語體現的各種能力,而不侷限於單純的網絡代理。
- Mecha 的部署模型,不侷限於 Sidecar 模式,Node 模式在某些場景下(如 Edge/IoT,Serverless FaaS)可能會是更好的方式。至少,Mecha下有機會按需選擇,而不是綁死在 Sidecar 模式上。
- Mecha 和 Micrologic 之間的交互是開放而有 API 標準的,Mecha 和 Micrologic 之間的“協議”體現在 API 上,而不是 TCP 通訊協議。這提供了一個契機:一個統一 Micrologic 和 Mecha 之間通訊方式的契機。
- Mecha 可以以聲明式的方式進行配置和控制,這非常符合雲原生的理念,同樣也使得 API 更關注於能力本身,而不是能力如何配置。
- 應用需要的能力如此之多(參見上面的圖:分佈式應用的四大需求),如果每個能力都對應一個代理(不管是 Node 還是 Sidecar),數量會非常誇張,帶來的運維壓力會很可怕。因此,如 Mecha 這個名字暗示的,運行時應該是整套的形式提供能力,而不是分散。
如果用一句話來總結,那麼我認為 Mecha 的本質應該是:
“面向應用的分佈式能力抽象層”
如 Service Mesh 的本質是服務間通訊的抽象層一樣,Mecha 的本質是應用需要的各種分佈式能力和原語,包括但不限於服務間通訊。
從這個角度上說,Mecha 覆蓋的範圍是 Service Mesh 的超集:畢竟 Service Mesh 只覆蓋到應用的部分需求(服務間通訊,還只限於同步/一對一/request-response 模式),還有更多的分佈式能力和原語有待覆蓋。
換一句話說,Mecha 的目標應該是:“將 Mesh 進行到底!”
Mecha 的優勢和未來
作者指出:Mecha 的好處是業務邏輯和越來越多的分佈式系統問題之間的鬆耦合。
下圖是業務邏輯和分佈式系統問題在不同架構中的耦合:
其實思路和 Service Mesh 是一脈相承的,只是覆蓋的分佈式能力更廣泛一些。
有一個問題:Mecha 會不會成為微服務架構的演進的下一個形態?我個人的答案:是,隨著雲原生的推進,分佈式能力(以傳統中間件為典型代表)下沉是大勢所趨,Mesh 化的範圍必然會繼續擴大,也就離 Mecha 的形態越來越近了。這也就是本文標題的立意所在,Mecha 會是微服務乃至雲原生的下一站。
微軟 Dapr
在介紹完 Mecha/Multiple Runtime 的理念之後,我們來看看目前微軟新推出來的 Dapr 項目 —— 這應該是業界第一個 Multiple Runtime 的開源實踐項目。
項目地址:https://github.com/dapr/dapr。
Dapr 介紹
Dapr 是 Distributed Application Runtime (分佈式應用運行時)的縮寫,官方介紹說 Dapr 是“一種可移植的,事件驅動的運行時,用於構建跨雲和邊緣的分佈式應用”。
Dapr 的詳細介紹是:
Dapr 是一種可移植的、Serverless 的、事件驅動的運行時,它使開發人員可以輕鬆構建彈性,無狀態和有狀態微服務,這些服務運行在雲和邊緣上,幷包含多種語言和開發框架。
Dapr 整理了構建微服務應用為開放,獨立的構建塊的最佳實踐,使您能夠使用自己選擇的語言和框架來構建可移植的應用程序。 每個構建塊都是獨立的,您可以在應用中使用其中的一個或多個。
Dapr 的功能和定位,下面這一張圖就可以概括了:
- 最底下基礎設施是各種雲平臺(主流公有云都支持)或者邊緣環境;
- 其上是 Dapr 提供的分佈式能力,Dapr 稱之為“building block”;
- 這些 building block 的能力,以統一的 API(支持 HTTP 和 gRPC)對外提供服務;
- 應用可以用各種語言編寫,然後通過 Dapr 提供的 API 使用這些能力,Dapr 也提供客戶端類庫來簡化對 API 的調用,實現了多語言的支持;
Dapr 提供的具體分佈式能力(building block)如下圖所示:
每個 building block 提供的具體能力請參加 Dapr 的官方文檔:
https://github.com/dapr/docs/tree/master/concepts
Dapr 的 API 例子
我們來看一下應用調用 Darp API 的例子,體驗一下使用 Dapr 的方式。
以 Service Invocation / 服務調用為例:
部署和調用方式與 Service Mesh/ Istio 極為相似,但是,差別在於:Dapr 是以提供 API 的方式提供 API 背後的能力,而不是提供提供協議代理的方式。
上圖,1 是 ServiceA 發起請求來調用一個遠程服務。其 HTTP request 如下所示:
POST/GET/PUT/DELETE http://localhost:<daprPort>/v1.0/invoke/<appId>/method/<method-name>
其中:
- 參數 daprPort 是 Dapr Runtime 啟動的監聽端口,用來接受應用的 outbound 請求;
- 參數 appId 是遠程應用在 Darp 中的關聯 ID,每個註冊到 Dapr 的應用都有一個唯一的 appId;
- 參數 method-name 是要調用的遠程應用的方法名或者 URL;
負載可以存放在 HTTP body 中隨請求發送,如 json。
注意,雖然都是提供相同的功能,這裡體現了 Dapr(或者說背後的 Mecha)和 Service Mesh 在方式上的差異:暴露 API 還是代理通訊協議。
我們看一個更明顯的例子,Dapr 提供的 “publish/subscriptions” 能力,讓應用可以方便的發佈消息,或者訂閱主題並接收消息。下圖是應用發佈消息,請求直接發給 Dapr 即可:
例子中,參數 topic 指定了消息要發往的主題(例子中是 deathStarStatus)。後續 Dapr 會完成將消息入 queue,然後推送到訂閱了該 topic 的應用。接收消息的方式也類似,不過這次是 Darp 主動發起:
- Dapr 首先會請求應用,諮詢應用需要訂閱那些主題(topic),如例子中應用返回的的 TopicA / TopicB;
- Dapr 實現主題訂閱,在接收到消息之後,再把消息發送給應用,通過 URL 參數的不同來區分不同的主題;
注意在這個調用期間,無論是收發消息,應用完全不用理會底層 pub/sub 的實現機制(比如是 Kafka,還是RocketMQ,還是其他公有云提供的消息機制),也完全不用引入該實現機制的客戶端 SDK,只是簡單的使用 Darp定義的 API 即可,從而實現了和底層的解耦,以及“廠商不綁定”。
為了進一步簡化調用的過程(畢竟發一個最簡單的 HTTP GET 請求也要應用實現 HTTP 協議的調用/連接池管理等),Dapr 提供了各個語言的 SDK,如 Java / Go / Python / dotNET / JavaScript / cpp / Rust 。另外同時提供 HTTP 客戶端和 gRPC 客戶端。
我們以 Java 為例,Java 的 client API 接口定義如下:
public interface DaprClient {
Mono<Void> publishEvent(String topic, Object event);
Mono<Void> invokeService(Verb verb, String appId, String method, Object request);
......
}
具體可見:
https://github.com/dapr/java-sdk/blob/master/sdk/src/main/java/io/dapr/client/DaprClient.java
分析和總結
前面介紹了Multiple Runtime / Mecha 的架構思想,以及參考實現之一的微軟 Dapr 項目。
由於 Multiple Runtime / Mecha 這個思想非常的新,剛剛提出不久,而微軟 Dapr 項目也是一個新出來的項目,不管是理論思想還是實踐都處於非常早期的狀態,也還沒有形成完善的方法論。
特別申明:以下內容更多是我個人當下的理解和感悟,僅代表個人意見,肯定有很多不成熟甚至謬誤的地方,歡迎指正和探討。
Mecha 和 Dapr 的啟示
- Mesh 模式應該推向更大的領域。
隨著雲原生的深入,應用需要的分佈式能力應該全面下沉,而不僅僅侷限於Servicemesh提供的服務間通訊能力;應用形態會朝純業務邏輯這個目標更進一步,應用更加的雲原生化。
這是大勢所趨,也是Mecha架構出現和發展的原動力。
- Mecha 強調是“提供能力”,而不是通訊代理。
Mecha 的使用方式和 Service Mesh 有非常大的差異:Mecha 強調的是提供分佈式能力給應用使用,這些能力最終以封裝完善的 API 的方式呈現。API 體現的是應用對能力的“需求”和“意願”,不涉及到如何實現,實現是 Mecha 的職責,採用什麼樣的實現也是由 Mecha 來控制。
在Service Mesh 下,不存在這個需求:Service Mesh 提供的是服務間通訊能力,這個能力是由 Sidecar 來提供,沒有其他更底層的實現,不存在隔離和替換的可能。受服務通訊協議和報文 schema 的限制,Service Mesh 只能做請求的“轉發”,能力聚焦在“如何轉發”上,沒有其他需要隔離和替代的能力。
當 Mecha 把能力擴展到 Servic Mesh 之外時,很多能力是由外部系統提供:比如 pub-sub 能力可以由不同的 Message Queue 實現;狀態管理能力可以連接不同的 Key-Value 實現。此時能力的隔離性和可替代性就成為關鍵需求:解耦應用和能力實現,容許 Mecha 替換底層實現(進而實現供應商不鎖定等)。
- 不強求“零侵入” 。
在 Service Mesh 中,“零侵入”是一個非常強調的特性,為此不惜引入 iptables 等流量劫持方案。“零侵入”在某些特殊場景下會發揮巨大的優勢,如舊有應用不做改造的前提下接入 Service Mesh。好處自然不言而喻,但零侵入也有自身的限制:客戶端必須能發出符合服務器端要求的網絡通訊請求,這個過程外部無法插手。
對於服務間通訊,這個不是大問題。但是對於其他能力,由於有和實現解耦的需求,再通過客戶端自行發起原生協議的請求就不合適了。因此,Mecha 中更傾向於採用低侵入的輕量級 SDK 方案,同樣也可以實現跨語言和跨平臺,只是需要付出實現各種語言 SDK 的代價。由於這個 SDK 足夠輕量,因此代價還不算很高。
而這些少量的工作量、少量的侵入,可以換取輕量級 SDK 能提供的各種便利和配合(簡單理解:開後門),可以實現能力的抽象和 API 的封裝。權衡利弊,Mecha 下更傾向於輕量級 SDK 方案。
- 不限定 Sidecar 部署 。
Sidecar 部署模式,存在資源佔用、維護成本增加等缺點,在某些情況下可能並不合適:
- 邊緣網絡、IoT 場景:資源非常有限,不適合啟動太多 Sidecar;
- FaaS 場景:應用自身足夠輕量,甚至比 Sidecar 還要輕量;
- Serverless 場景:Scale to Zero 時,對冷啟動速度有嚴格要求,Sidecar 的啟動和初始化可能拖累應用啟動速度;
Mecha 下,部署模式不限定於 Sidecar ,在合適時容許選擇 Node 模式,甚至 Node 模式和 Sidecar 模式混合使用。
- API 和配置是關鍵。
API 是分佈式能力的抽象,需要要對(開發上層業務應用的)客戶友好,簡單好用,穩定不變。這些 API 也需要標準化,被社區廣泛接受和採納,才能實現廠商不鎖定和自由遷移,提升客戶價值。
另外,API 還需要配合配置使用,在把能力抽象為 API 時,是不提供能力的細節控制的。這些控制將在運行時由 Mecha 根據配置實現,可以理解為:“API + 配置 = 完整的能力”。
API 和配置的制訂以及標準化,預計將會是 Mecha 成敗的關鍵。
Mecha 的精髓
Program to an interface, not an implementation.
Design Patterns: Elements of Reusable Object-Oriented Software (GOF, 1994)
Mecha 的精髓,要從上面這句名言開始:
- 在 Mecha 下,為了實現解耦和可替換, Runtime 隔離了底層實現,因此演變為:"Program to an Runtime, not an implementation."
- 考慮到 Runtime 不管是部署為 Sidecar 模式,還是部署為 Node 模式,都是 Localhost,因此有: “Program to an Localhost, not an implementation.”
- 為了簡化開發,Mecha 還是會提供輕量級 SDK,提供 API 作為能力的抽象:“Program to an API, not an implementation.”
- 考慮到 API 通常是以 interface 的形式提供,因此繞了一圈,Mecha 最後還是回到原點:“Program to an interface, not an implementation.”
個人理解,Mecha 的精髓就在於這幾個關鍵點:隔離/抽象/解耦/可替換。如下圖所示:
- 在 Mecha下,MicroLogic(也就是業務邏輯的代碼實現)不容許直接使用底層實現提供的分佈式能力;
- Mecha Runtime 將為 Micro Logic 提供分佈式能力,同時隔離應用和底層實現;
- 為了方便使用,提供輕量級 SDK,其中的 API 層實現了分佈式能力的抽象,應用只需面向 API 編程;
- 輕量級 SDK 和 Mecah Runtime 配合,完成對底層實現的解耦和可替換;
Mecha 的實現原則
在 Mecha 的實現上,我理解的原則是這樣:
- Runtime 是主力,要做厚;
- 輕量級 SDK 主要是給 Runtime 打配合,要做薄;
具體的職責劃分:
- 輕量級 SDK:實現多語言接入,低侵入(但不追求零侵入);
- API 接口:由輕量級 SDK 中提供統一,目標社區化+標準化,給開發者提供一致的編程體驗,同時提供可移植性;
- 應用:輕量級 SDK/Runtime 配合,提供各種分佈式能力,應用無感,只需簡單使用 API,不耦合底層實現;
在 Mecha 架構中,Runtime 自然是整個架構的核心,扮演類似 Service Mesh 中數據平面的角色:
- 所有分佈式能力使用的過程(包括訪問內部生態體系和訪問外部系統)都被 Runtime 接管和屏蔽實現;
- 通過 CRD/控制平面實現聲明式配置和管理(類似 Service Mesh);
- 部署方式上 Runtime 可以部署為 Sidecar 模式,或者 Node 模式,取決於具體需求,不強制;
備註:Mecha 有非常多的能力,實現上也有非常多的細節,這裡先做一個 High Level 的概述。細節後面會有一系列文章一一覆蓋,歡迎多交流討論。
Mecha 總結
大概是在3月初,當時我第一次閱讀 “Multi-Runtime Microservices Architecture” 這篇文章,有一種豁然開朗的感覺,尤其是有很多之前在反覆考慮和權衡但是下不了結論的問題,在這個文章中得到了清晰的解答。可謂受益匪淺。
在 Service Mesh 探索和實踐的這三年中,遇到很多問題,有很多之前沒有想到過的問題浮現。比如,以前一直覺得 Service Mesh 中引入 Sidecar 帶來的最大麻煩會是性能,但實際上,從目前的實踐看,Sidecar 引入後帶來的維護代價才是更令人頭疼的事情,相比之下 Sidecar 引入帶來的性能損失顯得無傷大雅。
總結一下我個人對 Mecha 架構的核心理解,主要是兩點:
- Mecha 是雲原生化和 Mesh 化的必然趨勢:雲原生在繼續發展,應用需要的分佈式能力需要繼續下沉,越來越多的能力會以 Sidecar 的形式出現,這是大勢所趨。但不可能出現一個應用部署十幾個 Sidecar 的局面,這會是運維地獄。因此,必然需要出現新的形態來解決 Sidecar 過多的問題,合併為一個或者多個 Sidecar 就會成為必然。
- Mecha 是 Service Mesh 模式的自然進化版本:Service Mesh 落地實踐三年了,效果一直並不理想,到了該反思反省的時候了;而且 Mecha 的範圍也遠不止服務間通訊,新的需求下應該有新的思考和突破。Service Mesh 現有的固定模式,在 Mecha 下可以嘗試打破以探索新的方式:不必拘泥於 Sidecar,試試 Node 模式;不必拘泥於通訊協議轉發,試試 Runtime 提供能力解耦底層實現;不必拘泥於零侵入,試試在應用中保留一個足夠輕的輕量級 SDK。
正如曾有說法,說“微服務是 SOA 實踐中正確的部分(the Good Part)”,我希望在 Mecha 的探索和實踐中,能夠從 Service Mesh 的實踐中吸取成功的經驗和失敗的教訓,希望 Mecha 也能成為 Service Mesh 的 Good Part。希望在雲原生的演進路線中,Mecha 可以繼微服務和 Service Mesh之後,成為雲原生落地實踐的下一站。
回到現實,目前 Mecha 和 Multi-Runtime 還是一個非常新的想法,Dapr 項目也才剛剛起步,Mecha 要探索的道路還很漫長,一切都還需要摸索著前進。
附錄:參考資料
在文章的最後,特別鳴謝 “Multi-Runtime Microservices Architecture”一文的作者 “Bilgin Ibryam”,我非常認可這篇文章中的思想和理念,分析歸納的非常到位,提煉和昇華的能力令人佩服。
作者介紹:
Red Hat 的首席架構師,Apache Software Foundation 的 committer 和成員。開源的佈道師,博客作者,偶爾演講,著有書籍 Kubernetes Patterns 和 Camel Design Patterns 。
本文參考了 Bilgin Ibryam 出品的如下內容:
- Multi-Runtime Microservices Architecture,作者 Bilgin Ibryam,Mecha的思想來自這篇文章,強烈推薦閱讀。也可以直接看我翻譯的版本 多運行時微服務架構。如前所述,建議在閱讀本文之前先閱讀這篇博客文章。
- The Evolution of Distributed Systems on Kubernetes : 作者 Bilgin Ibryam, 2020年3月在 QCon London的演講,依然強烈推薦。內容非常精彩,對 Kubernetes 上分佈式系統演進做了很好的總結和展望,當然也依然在佈道多運行時微服務架構的理念。本文的很多圖片 援引自這份PPT。