多運(yùn)行時微服務(wù)架構(gòu)實(shí)踐
創(chuàng)建良好的分布式應(yīng)用程序并非易事:這樣的系統(tǒng)通常會遵循 12 要素應(yīng)用程序和微服務(wù)原則。它們必須是無狀態(tài)的、可擴(kuò)展的、可配置的、獨(dú)立發(fā)布的、容器化的、可自動化的,有時甚至是事件驅(qū)動的和 serverless。創(chuàng)建之后,它們應(yīng)該很容易進(jìn)行升級,并且可以承受長期的維護(hù)。用今天的技術(shù)在這些互相競爭需求中找到一個良好的平衡點(diǎn)仍然需要付出艱苦的努力。
在本文中,我將探討分布式平臺該如何演化以實(shí)現(xiàn)這種平衡,更重要的是,在分布式系統(tǒng)的發(fā)展中還需要做些什么才能簡化可維護(hù)的分布式架構(gòu)的創(chuàng)建。
1. 分布式應(yīng)用程序的需求
為了討論方便起見,我把現(xiàn)代分布式應(yīng)用程序的需求分為 4 類,分別是生命周期(lifecycle)、網(wǎng)絡(luò)(networking)、狀態(tài)(state)和綁定(binding),并簡要地分析一下最近幾年中它們的發(fā)展情況。
生命周期
讓我們從基礎(chǔ)開始。當(dāng)我們編寫功能時,編程語言會指定生態(tài)系統(tǒng)中的可用庫、打包格式和運(yùn)行時。例如,Java 使用.jar 格式,所有的 Maven 依賴項(xiàng)作為一個生態(tài)系統(tǒng),而將 JVM 作為運(yùn)行時。如今,隨著發(fā)布周期變得更短,生命周期中更為重要的是以自動化的方式部署的能力、從錯誤中恢復(fù)的能力和擴(kuò)展服務(wù)的能力。這組能力廣泛地代表了應(yīng)用程序生命周期的需求。
網(wǎng)絡(luò)
如今,從某種意義上說,幾乎所有的應(yīng)用程序都是分布式應(yīng)用程序,因此,它們都需要網(wǎng)絡(luò)。但是,現(xiàn)代分布式系統(tǒng)需要從更廣泛的角度去掌握網(wǎng)絡(luò)。從服務(wù)發(fā)現(xiàn)和錯誤恢復(fù),到實(shí)現(xiàn)現(xiàn)代軟件發(fā)布技術(shù)和各種跟蹤及遙測。為了滿足我們的需要,我們甚至?xí)谶@個類別中包含不同的消息交換模式、點(diǎn)對點(diǎn)和發(fā)布 / 訂閱方式,以及智能路由機(jī)制。
狀態(tài)
當(dāng)我們在討論狀態(tài)時,通常是在討論服務(wù)的狀態(tài)以及為什么無狀態(tài)是更好的方案。但是,管理我們服務(wù)的平臺本身需要狀態(tài)。進(jìn)行可靠的服務(wù)編排和工作流、分布式單例、臨時調(diào)度(即 cron jobs)、冪等性(idempotency)、狀態(tài)化的錯誤恢復(fù)、緩存等等都需要它。這里所列出的功能都依賴于底層的狀態(tài)。盡管實(shí)際狀態(tài)管理不屬于本文討論的范圍,但是,我們感興趣的是分布式原語及其依賴于狀態(tài)的抽象。
綁定
分布式系統(tǒng)的組件不僅要相互通信,而且要和現(xiàn)代的或遺留的外部系統(tǒng)集成。這需要連接器(connector)能夠轉(zhuǎn)換各種協(xié)議、支持不同的消息交換模式,如輪詢、事件驅(qū)動、請求 / 答復(fù)、轉(zhuǎn)換消息格式,甚至能夠執(zhí)行自定義的錯誤恢復(fù)程序和安全機(jī)制。
排除一次性用例的情況,上面提到的內(nèi)容代表了創(chuàng)建良好分布式系統(tǒng)通用原語的一個很好的集合。如今,很多平臺都提供這類功能,但是,我們在本文中要講的是,在過去的 10 年中,我們使用這些功能的方式發(fā)生了什么變化,以及它在未來 10 年里會怎樣變化。為了進(jìn)行對比,我們來看看過去 10 年中基于 Java 的中間件是如何滿足這些需求的。
2. 傳統(tǒng)中間件的局限性
在知名的傳統(tǒng)解決方案中,有一個方案滿足了上述需求的老一代版本,那就是企業(yè)服務(wù)總線(ESB)及其變體,如面向消息的中間件、輕量級的集成框架等等。ESB 是一個中間件,它支持利用面向服務(wù)的架構(gòu)(即經(jīng)典的 SOA)實(shí)現(xiàn)異構(gòu)環(huán)境之間的互操作性。
盡管 ESB 可以提供良好的功能集,但是,ESB 的主要挑戰(zhàn)是單體架構(gòu)以及業(yè)務(wù)邏輯和平臺之間緊密的技術(shù)耦合,這導(dǎo)致了技術(shù)和組織的集中化。在這類系統(tǒng)中開發(fā)和部署服務(wù)時,它和分布性系統(tǒng)框架會緊密耦合,從而限制了服務(wù)的演化。在軟件生命的后期這才會變成一個明顯的問題。
ESB 面對每類需求都有一些問題和局限性,這使得 ESB 在現(xiàn)代已經(jīng)不再是可行的方案了,詳述如下。
生命周期
傳統(tǒng)的中間件通常只支持的一個語言運(yùn)行時,(比如 Java),這就限定了軟件該如何打包、哪些庫可用、它們打補(bǔ)丁的頻率等等。業(yè)務(wù)服務(wù)必須使用這些庫,這些庫與平臺緊密耦合并使用相同的語言編寫。在實(shí)踐中,這會導(dǎo)致服務(wù)和平臺的同步升級,從而妨礙服務(wù)和平臺之間實(shí)現(xiàn)獨(dú)立和定期的版本發(fā)布。
網(wǎng)絡(luò)
盡管傳統(tǒng)的中間件擁有高級的功能集,這些功能注重與其他內(nèi)部及外部服務(wù)的交互,但是,它有一些重大的缺陷。網(wǎng)絡(luò)功能集中于一種主要的編程語言及其相關(guān)的技術(shù)。對于 Java 語言,即 JMS、JDBC、JTA 等等。更重要的是,網(wǎng)絡(luò)問題和語義也深深地刻入了業(yè)務(wù)服務(wù)中。一些庫具有解決網(wǎng)絡(luò)問題的抽象(如曾經(jīng)流行一時的 Hystrix 項(xiàng)目),但是,該庫的抽象將自身的編程模型、交換模式和錯誤處理語義及庫本身“泄漏”到了服務(wù)之中。盡管可以方便地在一個位置編寫和讀取混合了網(wǎng)絡(luò)功能的完整業(yè)務(wù)邏輯,但是,這樣會把兩個問題緊密地耦合到一個實(shí)現(xiàn)中,最終會形成綁定在一起的演化路徑。
狀態(tài)
為了進(jìn)行可靠的服務(wù)編排、業(yè)務(wù)流程管理和實(shí)現(xiàn)模式(如 Saga 模式以及其他運(yùn)行緩慢的流程),平臺需要在后臺保持持久狀態(tài)。類似的,臨時操作(如觸發(fā)定時器和 cron job)都是基于狀態(tài)構(gòu)建的,并需要在分布式環(huán)境中對數(shù)據(jù)庫進(jìn)行集群和彈性處理。這里主要的約束是,與狀態(tài)交互的庫和接口沒有完全抽象出來,也沒有與服務(wù)運(yùn)行時完全解耦。通常,這些庫必須配置數(shù)據(jù)庫細(xì)節(jié),并且它們位于服務(wù)中,從而把語義和依賴項(xiàng)問題泄露到了應(yīng)用程序域中。
綁定
使用集成中間件的主要驅(qū)動因素之一是能夠使用不同協(xié)議、數(shù)據(jù)格式和消息交換模式連接各種其他系統(tǒng)。然而,這些連接器必須與應(yīng)用程序共存的事實(shí)意味著,依賴項(xiàng)必須與業(yè)務(wù)邏輯一起更新和打補(bǔ)丁。這樣的話,數(shù)據(jù)類型和數(shù)據(jù)格式必須在服務(wù)內(nèi)進(jìn)行來回地轉(zhuǎn)換。這意味著,必須根據(jù)消息交換模式構(gòu)造代碼和設(shè)計流程。上述的這幾個樣例場景說明了在傳統(tǒng)中間件中,即使是抽象的端點(diǎn)也會如何影響服務(wù)的實(shí)現(xiàn)。
3. 云原生的趨勢
傳統(tǒng)的中間件功能非常強(qiáng)大。它擁有所有必要的技術(shù)特性,但是,它缺乏快速改變和擴(kuò)展的能力,而這是現(xiàn)代數(shù)字業(yè)務(wù)需求所要求的。這是微服務(wù)架構(gòu)及其設(shè)計現(xiàn)代分布式應(yīng)用程序的指導(dǎo)原則正在解決的問題。
微服務(wù)背后的思想以及其技術(shù)需要推動了容器和 Kubernetes 的普及和廣泛使用。這開啟了一種新的創(chuàng)新方式,會影響未來幾年分布式應(yīng)用程序開發(fā)的方式。我們來看看 Kubernetes 及其相關(guān)的技術(shù)是如何影響每組需求的。
生命周期
容器和 Kubernetes 把我們打包、分發(fā)和部署應(yīng)用程序的方法演化成與編程語言無關(guān)的格式。關(guān)于 Kubernetes 模式和 Kubernetes 對程序開發(fā)人員的影響,有很多文章,這里我簡單說一下。請注意,對 Kubernetes 來說,需要管理的最小原語是容器,并且,它專注于在容器級別和流程模型上交付分布式原語。這意味著,在管理應(yīng)用程序的生命周期方面、健康檢查、恢復(fù)、部署和擴(kuò)展都做得很好,但是,在改進(jìn)分布式應(yīng)用程序的其他方面(如靈活的網(wǎng)絡(luò)、狀態(tài)管理和綁定)做得并不好,這些分布式應(yīng)用程序生存于容器內(nèi)部。
我們可能會指出,Kubernetes 擁有有狀態(tài)的工作負(fù)載、服務(wù)發(fā)現(xiàn)、cron job 及其他功能。這是事實(shí),但是,所有這些原語都在容器級別,并且在容器內(nèi)部,開發(fā)人員仍然必須使用特定于編程語言的庫來獲取更細(xì)粒度的功能,這些功能我們已經(jīng)在本文的開頭部分列出。這就是驅(qū)動 Envoy、Linkerd、Consul、Knative、Dapr、Camel-K 等等項(xiàng)目的原因。
網(wǎng)絡(luò)
事實(shí)證明,由 Kubernetes 提供的圍繞服務(wù)發(fā)現(xiàn)的基本網(wǎng)絡(luò)功能是一個良好的基礎(chǔ),但是,對于現(xiàn)代應(yīng)用程序來說還不夠。隨著微服務(wù)數(shù)量的增加和部署的加快,無需接觸服務(wù)就能實(shí)現(xiàn)更先進(jìn)的發(fā)布策略、管理安全、指標(biāo)、追蹤、從錯誤中恢復(fù)、模擬錯誤等功能變得越來越有吸引力,并產(chǎn)生了一種新的軟件類別,稱為服務(wù)網(wǎng)格。
這里有一個更令人興奮的趨勢,那就是將網(wǎng)絡(luò)相關(guān)的關(guān)注點(diǎn)從包含業(yè)務(wù)邏輯的服務(wù)轉(zhuǎn)移出來,放到一個單獨(dú)的運(yùn)行時中,這可能是邊車,也可能是節(jié)點(diǎn)級別的代理。今天,服務(wù)網(wǎng)格可以進(jìn)行更高級的路由,有助于測試、處理安全的某些問題,甚至可以使用特定于應(yīng)用程序的協(xié)議(例如,Envoy 支持 Kafka、MongoDB、Redis、MySQL 等)。盡管,服務(wù)網(wǎng)格作為一種解決方案,還沒有得到廣泛的采用,但是,它觸及了分布式系統(tǒng)真正的痛點(diǎn),我相信,它將找到適合自己生存的形式。
除了典型的服務(wù)網(wǎng)格外,還有其它項(xiàng)目,如 Skupper,它證實(shí)了把網(wǎng)絡(luò)能力放入外部運(yùn)行時代理的趨勢。Skupper 通過第 7 層虛擬網(wǎng)絡(luò)解決了多集群通信的難題,并提供了高級路由及連接功能。但是,它在每個 Kubernetes 命名空間運(yùn)行一個實(shí)例,而不是把 Skupper 嵌入業(yè)務(wù)服務(wù)運(yùn)行時。
總之,容器和 Kubernetes 在應(yīng)用程序的生命周期管理中向前邁出了重要的一步。服務(wù)網(wǎng)格及相關(guān)技術(shù)觸及了真正的痛點(diǎn),并為把應(yīng)用程序更多的責(zé)任向外轉(zhuǎn)移到代理打下了基礎(chǔ)。我們來看看接下來的事。
狀態(tài)
我們在前面列出了依賴于狀態(tài)的主要集成原語。狀態(tài)的管理比較困難,應(yīng)該把它委派給專門的存儲軟件和托管服務(wù)。這不是本文的主題,但是,使用狀態(tài),以語言無關(guān)的抽象方式來幫助集成用例才是主題。如今,大家做了很多努力,試圖在語言中立的抽象背后面提供狀態(tài)化的原語。對于基于云的服務(wù)來講,狀態(tài)化工作流的管理是必備功能,例如 AWS 的 Step 函數(shù)、Azure Durable 函數(shù)等。在基于容器的部署中,CloudState 和 Dapr 都依賴邊車模型以提供分布式應(yīng)用程序中狀態(tài)化抽象更好的解耦。
我希望,把前面列出的狀態(tài)化功能也都抽象到一個獨(dú)立的運(yùn)行時。這意味著,工作流管理、單例、冪等、事務(wù)管理、cron job 觸發(fā)器和狀態(tài)化錯誤處理都在邊車(或主機(jī)級別的代理)中可靠地發(fā)生,而不是存在于服務(wù)中。業(yè)務(wù)邏輯不需要在應(yīng)用程序中包括這類依賴項(xiàng)和語義,它可以從綁定環(huán)境中聲明式地請求這類行為。例如,邊車可以充當(dāng) cron job 觸發(fā)器、冪等消費(fèi)者和工作流管理器,并且自定義業(yè)務(wù)邏輯可以作為回調(diào)調(diào)用或在工作流、錯誤處理、臨時調(diào)用或唯一冪等請求等的某些階段插入。
另一個狀態(tài)化的用例是緩存。無論是服務(wù)網(wǎng)格層執(zhí)行的請求緩存,還是用 Infinispan、Redis、Hazelcast 等進(jìn)行的數(shù)據(jù)緩存,有一些把緩存功能推到應(yīng)用程序運(yùn)行時之外的示例。
綁定
盡管我們一直在討論從應(yīng)用程序運(yùn)行時解耦所有分布式需求這個主題,但是這種趨勢也伴隨著綁定。連接器、協(xié)議轉(zhuǎn)換、消息轉(zhuǎn)換、錯誤處理和安全中介都可以移出服務(wù)運(yùn)行時。我們還沒到那個階段,但是,有幾個項(xiàng)目在朝這個方向進(jìn)行嘗試,如:Knative 和 Dapr。把所有這些職責(zé)移出應(yīng)用程序運(yùn)行時將導(dǎo)致更小型的專注于業(yè)務(wù)邏輯的代碼。這類代碼將生存于獨(dú)立于分布式系統(tǒng)需求的運(yùn)行時中,可以作為預(yù)打包的功能使用。
Apache Camel-K 項(xiàng)目采用了另一種有趣的方法。該項(xiàng)目依賴于一個智能 Kubernetes 操作符(Kubernetes Operator,該操作符利用來自 Kubernetes 和 Knative 附加的平臺能力構(gòu)建應(yīng)用程序運(yùn)行時),而不是將運(yùn)行時代理和主應(yīng)用程序放到一起。在這里,該代理是負(fù)責(zé)應(yīng)用程序要求的操作符,其中包括分布式系統(tǒng)原語。區(qū)別在于,有些分布式原語被添加到應(yīng)用程序運(yùn)行時中,而有些是在平臺(也可能包括邊車)中實(shí)現(xiàn)的。
4. 未來架構(gòu)的趨勢
從廣義上看,我們可以總結(jié)為,通過把功能移到平臺級別,分布式應(yīng)用程序的商業(yè)化達(dá)到了新領(lǐng)域。除了生命周期之外,現(xiàn)在我們可以將網(wǎng)絡(luò)觀察、狀態(tài)抽象、聲明性事件以及端點(diǎn)綁定也視為有現(xiàn)成解決方案的領(lǐng)域,而 EIP 則是該列表上的下一個。有趣的是,商業(yè)化正在使用進(jìn)程外模型(邊車)進(jìn)行功能擴(kuò)展,而不是運(yùn)行時庫或單純的平臺功能(如新 Kubernetes 功能)。
通過把所有傳統(tǒng)中間件功能(也即 ESB)移到其他運(yùn)行時,我們正在接近實(shí)現(xiàn)整個循環(huán),不久之后,我們在服務(wù)中唯一要做的就是編寫業(yè)務(wù)邏輯。
與傳統(tǒng) ESB 時代相比,這個架構(gòu)更好地解耦了業(yè)務(wù)邏輯和平臺,但還沒完全解耦。很多分布式原語,如經(jīng)典的企業(yè)集成模式(Enterprise Integration Pattern,簡稱 EIP): 拆分器、聚合器、過濾器、基于內(nèi)容的路由器;以及流處理模式(映射、過濾、折疊、聯(lián)接、合并、滑動窗口)仍然需要包含在業(yè)務(wù)邏輯運(yùn)行時中,很多其他應(yīng)用程序依賴于多個不同的及重疊的平臺附加組件中。
如果我們把在不同領(lǐng)域中進(jìn)行創(chuàng)新的不同云原生項(xiàng)目疊加起來,那么,我們最終會看到這張圖,如下所示:
這里的圖只是用于說明,它故意選擇了有代表性的項(xiàng)目,并把它們映射為分布式原語的一種。實(shí)際上,我們不會同時使用所有這些項(xiàng)目,因?yàn)樗鼈冎械囊恍┦侵丿B的,并且工作負(fù)載模型也是不兼容的。如何來講解這張圖?
- Kubernetes 和容器在多語言應(yīng)用程序的生命周期管理中取得了巨大的飛躍,并為未來的創(chuàng)新奠定了基礎(chǔ)。
- 服務(wù)網(wǎng)格技術(shù)在 Kubernetes 之上利用高級的網(wǎng)絡(luò)功能進(jìn)一步進(jìn)行了改善,并開始涉足應(yīng)用程序方面。
- 盡管 Knative 憑借其快速擴(kuò)展主要專注于 serverless 類型的工作負(fù)載,但是,它也滿足了服務(wù)編排和事件驅(qū)動的綁定需求。
- Dapr 建立在 Kubernetes、Knative 和服務(wù)網(wǎng)格的思想之上,并深入應(yīng)用程序運(yùn)行時以解決狀態(tài)化工作負(fù)載、綁定和集成的需求,充當(dāng)現(xiàn)代分布式中間件。
這張圖能夠幫助我們看到,很可能在將來,我們最終會使用多運(yùn)行時來實(shí)現(xiàn)分布式系統(tǒng)。多運(yùn)行時,不是因?yàn)橛卸鄠€微服務(wù),而是因?yàn)槊總€微服務(wù)將由多個運(yùn)行時構(gòu)成,很可能會有兩個,即自定義業(yè)務(wù)邏輯運(yùn)行時和分布式原語運(yùn)行時。
5. 引入多運(yùn)行時微服務(wù)
以下是正在形成的多運(yùn)行時微服務(wù)架構(gòu)的概述。
你是否記得在電影《阿凡達(dá)》中,科學(xué)家開發(fā)的增強(qiáng)機(jī)動平臺(Amplified Mobility Platform,簡稱 AMP)“機(jī)甲戰(zhàn)衣(mech suits)”以進(jìn)入荒野去探索潘多拉星球(Pandora)?這個多運(yùn)行時架構(gòu)和 Mecha- 戰(zhàn)衣類似,都能為人類驅(qū)動者提供超能力。在電影中,我們把人類放入戰(zhàn)衣以獲得力量及毀滅性武器。在這個軟件架構(gòu)中,我們讓業(yè)務(wù)邏輯(指的是微邏輯)形成應(yīng)用程序的核心,而邊車 mecha 組件提供強(qiáng)大的開箱即用的分布式原語。這個微邏輯和 mecha 功能組合起來形成一個多運(yùn)行時微服務(wù),該微服務(wù)使用進(jìn)程外功能以滿足其分布式系統(tǒng)的需求 。最棒的是,Avatar 2 即將出手來幫助推廣這個架構(gòu)。這樣我們終于可以在所有的軟件大會上用非凡的機(jī)甲照片來替換老式的挎斗摩托車照片了;)。下面,我們來看看這個軟件架構(gòu)的細(xì)節(jié)。
這是一個有兩個組件的模型,類似于客戶端 - 服務(wù)器架構(gòu),其中每個組件都是獨(dú)立的運(yùn)行時。它和純粹客戶端 - 服務(wù)器架構(gòu)的區(qū)別在于,這兩個組件都位于同一個主機(jī)中,并且在它們之間有可靠的網(wǎng)絡(luò),這一點(diǎn)無需擔(dān)心。兩個組件同等重要,它們可以在任何一個方向上初始化操作并充當(dāng)客戶端或服務(wù)器。組件之一稱為微邏輯(Micrologic),它包含了幾乎所有從分布式系統(tǒng)關(guān)注點(diǎn)中剝離出來的最小業(yè)務(wù)邏輯。在一起的另一個部件叫 Mecha,它提供了我們一直在本文中討論的所有分布式系統(tǒng)功能(生命周期除外,它是平臺的功能)。
微邏輯和 Mecha(即邊車模型)可能是一對一的部署,也可以多個微邏輯運(yùn)行時共享 Mecha。第一種模型最適合 Kubernetes 等環(huán)境,而后者適用于邊緣部署。
微邏輯運(yùn)行時特征
我們簡要地探討一下微邏輯運(yùn)行時的一些特征:
- 微邏輯組件本身不是微服務(wù)。它包含微服務(wù)會有的業(yè)務(wù)邏輯,但是,該邏輯只能和 Mecha 組件結(jié)合使用。另一方面,微服務(wù)是自包含的,整體功能的片段或部分處理流沒有分散到其他的運(yùn)行時。微邏輯及其對應(yīng)的 Mecha 組合形成了微服務(wù)。
- 這也不是函數(shù)或 serverless 架構(gòu)。serverless 主要以其托管的快速擴(kuò)展和歸零能力而聞名。在 serverless 架構(gòu)中,函數(shù)只實(shí)現(xiàn)單個操作,因?yàn)檫@是擴(kuò)展的單位。在這一方面,函數(shù)與微邏輯不同,微邏輯實(shí)現(xiàn)多個操作,但是,實(shí)現(xiàn)不是端到端的。更重要的是,操作的實(shí)現(xiàn)分散于 Mecha 和微服務(wù)運(yùn)行時。
- 這是客戶端 - 服務(wù)器架構(gòu)的特殊形式,針對無需編碼就使用眾所周知的分布式原語進(jìn)行了優(yōu)化。另外,如果我們假設(shè) Mecha 扮演服務(wù)器的角色,那么,每個實(shí)例必須專門配置如何與每個的客戶端一起工作。它不是一個旨在支持多個客戶端的同時又是一個典型的客戶端 - 服務(wù)器架構(gòu)的通用服務(wù)器實(shí)例。
- 微邏輯中的用戶代碼沒有直接和其他系統(tǒng)交互,也沒有實(shí)現(xiàn)任何分布式系統(tǒng)原語。它通過事實(shí)標(biāo)準(zhǔn)(如 HTTP/gRPC、CloudEvents 規(guī)范)和 Mecha 交互,并且,在配置好的步驟和機(jī)制的指導(dǎo)下,Mecha 利用豐富的功能與其他系統(tǒng)通信。
- 盡管微邏輯只負(fù)責(zé)實(shí)現(xiàn)從分布式系統(tǒng)問題中剝離出來的業(yè)務(wù)邏輯,但是,它仍然必須至少實(shí)現(xiàn)一些 API。它必須允許 Mecha 和平臺通過預(yù)定義的 API 和協(xié)議(例如,遵循 Kubernetes 部署的云原生設(shè)計原則)與之交互。
Mecha 運(yùn)行時特征
以下是一些 Mecha 運(yùn)行時的特征:
- Mecha 是一個通用的、高度可配置的、可重用的組件,提供分布式原語作為現(xiàn)成的功能。
- Mecha 的每個實(shí)例必須配置成與一個微邏輯組件(邊車模型)一起工作,或者配置成與一些組件共享。
- Mecha 不對微邏輯運(yùn)行時做任何假設(shè)。它與利用開放協(xié)議和格式(如 HTTP/gRPC、JSON、Protobuf、CloudEvents)的多語言微服務(wù)或甚至單體系統(tǒng)一起工作。
- Mecha 用簡單文本格式(如 YAML、JSON)進(jìn)行聲明式配置,這些格式規(guī)定了要啟用什么功能以及如何把它們綁定到微邏輯端點(diǎn)上。對于特定的 API 交互操作,可以為 Mecha 附加規(guī)范,如 OpenAPI、AsyncAPI、ANSI-SQL 等。對于由多個步驟構(gòu)成的狀態(tài)化工作流,可以使用如 亞馬遜狀態(tài)編程語言(Amazon State Language)的規(guī)范。對無狀態(tài)集成,可以用類似 Camel-K YAML DSL 的方法使用企業(yè)集成模式(Enterprise Integration Patterns,簡稱 EIPs)。這里的關(guān)鍵之處是,所有這些都是簡單的、基于文本的、聲明式的、多語言定義的,Mecha 可以不需要編碼就能實(shí)現(xiàn)。請注意,這些是未來派的預(yù)測,目前,沒有用于狀態(tài)化編排或 EIP 的 Mecha,但是,我期望現(xiàn)有的 Mecha(Envoy、Dapr、Cloudstate 等)很快開始添加這類功能。Mecha 是應(yīng)用程序級別的分布式原語抽象層。
- 與其依賴于用于不同目的(如網(wǎng)絡(luò)代理、緩存代理、綁定代理)的多個代理,不如有一個提供所有這些功能的 Mecha。某些能力的實(shí)現(xiàn)(如存儲、消息持久性、緩存等)將會有其他的云或自建的服務(wù)插入并支持。
- 關(guān)于生命周期管理的一些分布式系統(tǒng)問題由管理平臺(比如,Kubernetes 或其他云服務(wù))而不是由使用 Open App Model 等通用開放規(guī)范的 Mecha 運(yùn)行時來提供是合理的。
這個架構(gòu)的主要好處是什么?
它的好處是業(yè)務(wù)邏輯和不斷增長的分布式系統(tǒng)問題之間的松耦合。軟件系統(tǒng)的這兩個元素有完全不同的動態(tài)。業(yè)務(wù)邏輯總是唯一的,代碼是自定義的和內(nèi)部編寫的。它經(jīng)常更改,具體取決于組織的優(yōu)先級和執(zhí)行能力。另一方面,分布式原語是用來解決本文所列的那些問題的,并且大家都知道。它們由軟件供應(yīng)商開發(fā)并作為庫、容器或服務(wù)使用。代碼隨著供應(yīng)商的優(yōu)先級、發(fā)布周期、安全補(bǔ)丁、開源管理規(guī)則等進(jìn)行更改。這兩者相互之間沒有什么可見性,也無法相互控制。
微服務(wù)原則有助于通過限界上下文解耦不同的業(yè)務(wù)領(lǐng)域,其中每個微服務(wù)可以獨(dú)立地發(fā)展。但是,微服務(wù)架構(gòu)沒有解決業(yè)務(wù)邏輯與中間件問題耦合帶來的難題。對于某些缺少集成場景的微服務(wù)來說,這可能不是一個大問題。但是,如果我們的領(lǐng)域涉及復(fù)雜的集成(每個人的情況都越來越復(fù)雜),遵循微服務(wù)原則將無助于我們避免與中間件耦合。即使中間件被表示為包含在我們的微服務(wù)中的庫,在我們開始遷移和改變這些庫的時候,耦合也將變得明顯。我們需要的分布式原語越多,就越容易耦合到集成平臺中。通過預(yù)定義的 API 而不是庫,把中間件作為獨(dú)立的運(yùn)行時 / 進(jìn)程使用,有助于松耦合并實(shí)現(xiàn)每個組件的獨(dú)立發(fā)展。
這也是一種為供應(yīng)商分發(fā)和維護(hù)復(fù)雜中間件軟件的更好的方法。只要與中間件是通過開放 API 和標(biāo)準(zhǔn)的進(jìn)程間通信進(jìn)行交互的,那么,軟件供應(yīng)商就可以按其節(jié)奏自由地發(fā)布補(bǔ)丁和更新。用戶可以自由地使用其喜歡的編程語言、庫、運(yùn)行時、部署方式和流程。
這個架構(gòu)的主要缺點(diǎn)是什么?
進(jìn)程間通信。事實(shí)上,分布式系統(tǒng)的業(yè)務(wù)邏輯和中間件機(jī)制(Mecha 就來自 mechanics 這個詞)處于不同的運(yùn)行時,這需要采用 HTTP 或 gRPC 調(diào)用而不是進(jìn)程內(nèi)的方式調(diào)用。但是,請注意,這不是一個轉(zhuǎn)到另一臺主機(jī)或數(shù)據(jù)中心的網(wǎng)絡(luò)調(diào)用。微邏輯運(yùn)行時和 Mecha 應(yīng)該在同一個主機(jī)中共存,因此延遲很低,并且出現(xiàn)網(wǎng)絡(luò)問題的可能性最小。
復(fù)雜性。接下來的問題是,是否值得進(jìn)行如此復(fù)雜的開發(fā)并維護(hù)這樣的系統(tǒng)以獲得收益。我認(rèn)為,答案越來越傾向于“是”。分布式系統(tǒng)的需求在增加,發(fā)布周期變得越來越短。該架構(gòu)針對該領(lǐng)域進(jìn)行了優(yōu)化。前段時間,我曾經(jīng)寫道,未來的開發(fā)人員必須具備混合開發(fā)技能。該架構(gòu)進(jìn)一步證實(shí)并加強(qiáng)了這個趨勢。應(yīng)用程序的一部分將用更高級的編程語言編寫,而部分功能將由必須進(jìn)行聲明式配置的現(xiàn)成組件提供。這兩個部分的連接沒有發(fā)生在編譯期,也沒有在啟動時通過進(jìn)程內(nèi)依賴項(xiàng)注入而實(shí)現(xiàn),而是在部署的時候通過進(jìn)程間通信發(fā)生的。該模型可實(shí)現(xiàn)更高的軟件重用率和更快的變更速度。
微服務(wù)之后并不是函數(shù)
微服務(wù)架構(gòu)有個明確的目標(biāo)。它對變更進(jìn)行優(yōu)化。通過把應(yīng)用程序切分到業(yè)務(wù)域,該架構(gòu)借助服務(wù)為軟件演化和可維護(hù)性提供了最優(yōu)的服務(wù)邊界,這些服務(wù)是解耦的,由獨(dú)立的團(tuán)隊(duì)管理,并以獨(dú)立的節(jié)奏發(fā)布。
如果我們來看看 serverless 架構(gòu)的編程模型,會發(fā)現(xiàn)它主要是基于函數(shù)的。函數(shù)針對可擴(kuò)展性進(jìn)行了優(yōu)化。借助函數(shù),我們把每個操作分解為一個獨(dú)立的組件,從而可以根據(jù)需要,快速且獨(dú)立地擴(kuò)展。在這個模型中,部署粒度是一個函數(shù)。選擇函數(shù)的原因是,它的代碼結(jié)構(gòu)的輸入的速度與擴(kuò)展行為直接相關(guān)。這個架構(gòu)針對極端的可擴(kuò)展性而不是復(fù)雜系統(tǒng)的長期維護(hù)性進(jìn)行了優(yōu)化。
我們從 AWS Lambda 的流行程度及其完全托管的運(yùn)維來看,serverless 的其他方面又是什么呢?“AWS Serverless”針對供應(yīng)速度進(jìn)行了優(yōu)化,以彌補(bǔ)缺乏控制和鎖定的代價。但是,完全托管不是應(yīng)用程序架構(gòu),而是軟件消費(fèi)模型。它在功能上是正交的,與使用基于 SaaS 的平臺類似,在理想情況下適用于任何架構(gòu),無論是單體、微服務(wù)、Mecha 還是函數(shù)。在很多方面,AWS Lambda 類似于完全托管的 Mecha 架構(gòu),但有一個很大的不同:Mecha 沒有強(qiáng)制使用函數(shù)模型,相反,它允許圍繞業(yè)務(wù)域使用更具凝聚力的代碼構(gòu)造,而與所有中間件無關(guān)。
另一方面,Mecha 架構(gòu)針對中間件的獨(dú)立性優(yōu)化了微服務(wù)。盡管微服務(wù)彼此獨(dú)立,但是,它們嚴(yán)重依賴嵌入式分布式原語。Mecha 架構(gòu)把這兩個問題分成獨(dú)立的運(yùn)行時,允許它們通過獨(dú)立的團(tuán)隊(duì)進(jìn)行獨(dú)立的發(fā)布。這種解耦改善了日常的運(yùn)維(如補(bǔ)丁和更新)并提高了業(yè)務(wù)邏輯內(nèi)聚單位的長期維護(hù)性。Mecha 架構(gòu)是微服務(wù)架構(gòu)的自然發(fā)展,根據(jù)引發(fā)最大摩擦的邊界來分割軟件。與函數(shù)模型相比,該優(yōu)化以軟件重用和演化的方式提供了更多的好處,函數(shù)模型通過以代碼的過度分布為代價為優(yōu)化提供了極大的可擴(kuò)展性。
6. 結(jié)論
分布式應(yīng)用程序有很多要求。創(chuàng)建有效的分布式系統(tǒng)需要多種技術(shù)和好的集成方法。盡管傳統(tǒng)的單體中間件提供了分布式系統(tǒng)要求的所有必需的技術(shù)功能,但是,它缺乏快速變化、適應(yīng)和擴(kuò)展的能力,而這些是業(yè)務(wù)所需要的。這就是為什么基于微服務(wù)架構(gòu)促成容器和 Kubernetes 的快速普及背后的原因,借助云原生領(lǐng)域最新的發(fā)展,現(xiàn)在,我們回到了原點(diǎn),把所有傳統(tǒng)中間件功能遷移到平臺和現(xiàn)成的輔助運(yùn)行時。應(yīng)用程序功能的商品化主要使用進(jìn)程外模型而不是運(yùn)行時庫或純平臺功能進(jìn)行功能擴(kuò)展。這意味著,將來我們很可能使用多運(yùn)行時來實(shí)現(xiàn)分布式系統(tǒng)。多運(yùn)行時,不是因?yàn)橛卸鄠€微服務(wù),而是因?yàn)槊總€微服務(wù)將有多運(yùn)行時構(gòu)成,有用于自定義微業(yè)務(wù)邏輯的運(yùn)行時以及用于分布式原語的現(xiàn)成的可配置的運(yùn)行時。
作者簡介
Bilgin Ibryam 是紅帽(Red Hat)的首席架構(gòu)師、Apache 軟件基金會(Apache Software Foundation)的提交者和成員。他熱衷于推廣開源、寫博客,偶爾還參與技術(shù)演講。他是《Kubernetes 模式(Kubernetes Patterns)》和《Camel 設(shè)計模式(Camel Design Patterns)》的作者。在日常工作中,Bilgin 樂于指導(dǎo)、編碼并領(lǐng)導(dǎo)開發(fā)人員成功地構(gòu)建開源解決方案。目前,他專注于區(qū)塊鏈、分布式系統(tǒng)、微服務(wù)、開發(fā)運(yùn)維和云原生應(yīng)用程序開發(fā)。