天天看點

MOSN 子項目 Layotto:開啟服務網格+應用運作時新篇章

作者 | 馬振軍

來源 | 金融級分布式架構公衆号

作者簡介:

馬振軍,花名古今,在基礎架構領域耕耘多年,對 Service Mesh 有深度實踐經驗,目前在螞蟻集團中間件團隊負責 MOSN、Layotto 等項目的開發工作。

Layotto 官方 GitHub 位址:

https://github.com/mosn/layotto

點選觀看現場視訊

Service Mesh 在微服務領域已經非常流行,越來越多的公司開始在内部落地,螞蟻從 Service Mesh 剛出現的時候開始,就一直在這個方向上大力投入,到目前為止,内部的 Mesh 方案已經覆寫數千個應用、數十萬容器并且經過了多次大促考驗,Service Mesh 帶來的業務解耦,平滑更新等優勢大大提高了中間件的疊代效率。

在大規模落地以後,我們又遇到了新的問題,本文主要對 Service Mesh 在螞蟻内部落地情況進行回顧總結,并分享對 Service Mesh 落地後遇到的新問題的解決方案。

一、Service Mesh 回顧與總結

A、Service Mesh 的初衷

MOSN 子項目 Layotto:開啟服務網格+應用運作時新篇章

在微服務架構下,基礎架構團隊一般會為應用提供一個封裝了各種服務治理能力的 SDK,這種做法雖然保障了應用的正常運作,但缺點也非常明顯,每次基礎架構團隊疊代一個新功能都需要業務方參與更新才能使用,尤其是 bugfix 版本,往往需要強推業務方更新,這裡面的痛苦程度每一個基礎架構團隊成員都深有體會。

伴随着更新的困難,随之而來的就是應用使用的 SDK 版本差别非常大,生産環境同時跑着各種版本的 SDK,這種現象又會讓新功能的疊代必須考慮各種相容,就好像帶着枷鎖前進一般,這樣随着不斷疊代,會讓代碼維護非常困難,有些祖傳邏輯更是一不小心就會掉坑裡。

同時這種“重”SDK 的開發模式,導緻異構語言的治理能力非常薄弱,如果想為各種程式設計語言都提供一個功能完整且能持續疊代的 SDK 其中的成本可想而知。

18 年的時候,Service Mesh 在國内持續火爆,這種架構理念旨在把服務治理能力跟業務解耦,讓兩者通過程序級别的通信方式進行互動。在這種架構模式下,服務治理能力從應用中剝離,運作在獨立的程序中,疊代更新跟業務程序無關,這就可以讓各種服務治理能力快速疊代,并且由于更新成本低,是以每個版本都可以全部更新,解決了曆史包袱問題,同時 SDK 變“輕”直接降低了異構語言的治理門檻,再也不用為需要給各個語言開發相同服務治理能力的 SDK 頭疼了。

B、Service Mesh 落地現狀

MOSN 子項目 Layotto:開啟服務網格+應用運作時新篇章

螞蟻很快意識到了 Service Mesh 的價值,全力投入到這個方向,用 Go 語言開發了 MOSN 這樣可以對标 envoy 的優秀資料面,全權負責服務路由,負載均衡,熔斷限流等能力的建設,大大加快了公司内部落地 Service Mesh 的進度。

現在 MOSN 在螞蟻内部已經覆寫了數千個應用、數十萬容器,新建立的應用預設接入 MOSN,形成閉環。而且在大家最關心的資源占用、性能損耗方面 MOSN 也交出了一份讓人滿意的答卷:

  1. RT 小于 0.2ms
  2. CPU 占用增加 0%~2%
  3. 記憶體消耗增長小于 15M

由于 Service Mesh 降低了異構語言的服務治理門檻,NodeJS、C++等異構技術棧也在持續接入到 MOSN 中。

在看到 RPC 能力 Mesh 化帶來的巨大收益之後,螞蟻内部還把 MQ,Cache,Config 等中間件能力都進行了 Mesh 化改造,下沉到 MOSN,提高了中間件産品整體的疊代效率。

C、新的挑戰

  1. 應用跟基礎設施強綁定
MOSN 子項目 Layotto:開啟服務網格+應用運作時新篇章

一個現代分布式應用,往往會同時依賴 RPC、Cache、MQ、Config 等各種分布式能力來完成業務邏輯的處理。

當初看到 RPC 下沉的紅利以後,其他各種能力也都快速下沉。初期,大家都會以自己最熟悉的方式來開發,這就導緻沒有統一的規劃管理,如上圖所示,應用依賴了各種基礎設施的 SDK,而每種 SDK 又以自己特有的方式跟 MOSN 進行互動,使用的往往都是由原生基礎設施提供的私有協定,這直接導緻了複雜的中間件能力雖然下沉,但應用本質上還是被綁定到了基礎設施,比如想把緩存從 Redis 遷移到 Memcache 的話,仍舊需要業務方更新 SDK,這種問題在應用上雲的大趨勢下表現的更為突出,試想一下,如果一個應用要部署在雲上,由于該應用依賴了各種基礎設施,勢必要先把整個基礎設施搬到雲上才能讓應用順利部署,這其中的成本可想而知。

是以如何讓應用跟基礎設施解綁,使其具備可移植能力,能夠無感覺跨平台部署是我們面臨的第一個問題。

  1. 異構語言接入成本高
MOSN 子項目 Layotto:開啟服務網格+應用運作時新篇章

事實證明 Service Mesh 确實降低了異構語言的接入門檻,但在越來越多的基礎能力下沉到 MOSN 以後,我們逐漸意識到為了讓應用跟 MOSN 互動,各種 SDK 裡都需要對通信協定,序列化協定進行開發,如果再加上需要對各種異構語言都提供相同的功能,那維護難度就會成倍上漲,

Service Mesh 讓重 SDK 成為了曆史,但對于現在各種程式設計語言百花齊放、各種應用又強依賴基礎設施的場景來說,我們發現現有的 SDK 還不夠薄,異構語言接入的門檻還不夠低,如何進一步降低異構語言的接入門檻是我們面臨的第二個問題。

二、Multi Runtime 理論概述

A、什麼是 Runtime?

MOSN 子項目 Layotto:開啟服務網格+應用運作時新篇章

20 年初的時候,Bilgin lbryam 發表了一篇名為

Multi-Runtime Microservices Architecture

的文章,裡面對微服務架構下一階段的形态進行了讨論。

如上圖所示,作者把分布式服務的需求進行了抽象,總共分為了四大類:

1.生命周期(Lifecycle)

主要指應用的編譯、打包、部署等事情,在雲原生的大趨勢下基本被 docker、kubernetes 承包。

2.網絡(Networking)

可靠的網絡是微服務之間進行通信的基本保障,Service Mesh 正是在這方面做了嘗試,目前 MOSN、envoy 等流行的資料面的穩定性、實用性都已經得到了充分驗證。

3.狀态(State)

分布式系統需要的服務編排,工作流,分布式單例,排程,幂等性,有狀态的錯誤恢複,緩存等操作都可以統一歸為底層的狀态管理。

4.綁定(Binding)

在分布式系統中,不僅需要跟其他系統通信,還需要內建各種外部系統,是以對于協定轉換,多種互動模型、錯誤恢複流程等功能也都有強依賴。

明确了需求以後,借鑒了 Service Mesh 的思路,作者對分布式服務的架構演進進行了如下總結:

MOSN 子項目 Layotto:開啟服務網格+應用運作時新篇章

第一階段就是把各種基礎設施能力從應用中剝離解耦,通通變成獨立 sidecar 模型伴随着應用一起運作。

第二階段是把各種 sidecar 提供的能力統一抽象成若幹個 Runtime,這樣應用從面向基礎元件開發就演變成了面向各種分布式能力開發,徹底屏蔽掉了底層實作細節,而且由于是面向能力,除了調用提供各種能力的 API 之外,應用再也不需要依賴各種各樣基礎設施提供的 SDK 了。

作者的思路跟我們希望解決的問題一緻,我們決定使用 Runtime 的理念來解決 Service Mesh 發展到現在所遇到的新問題。

B、Service Mesh vs Runtime

MOSN 子項目 Layotto:開啟服務網格+應用運作時新篇章

為了讓大家對 Runtime 有一個更加清晰的認識,上圖針對 Service Mesh 跟 Runtime 兩種理念的定位、互動方式、通信協定以及能力豐富度進行了總結,可以看到相比 Service Mesh 而言,Runtime 提供了語義明确、能力豐富的 API,可以讓應用跟它的互動變得更加簡單直接。

三、MOSN 子項目 Layotto

A、dapr 調研

MOSN 子項目 Layotto:開啟服務網格+應用運作時新篇章

dapr 是社群中一款知名的 Runtime 實作産品,活躍度也比較高,是以我們首先調研了 dapr 的情況,發現 dapr 具有如下優勢:

  1. 提供了多種分布式能力,API 定義清晰,基本能滿足一般的使用場景。
  2. 針對各種能力都提供了不同的實作元件,基本涵蓋了常用的中間件産品,使用者可以根據需要自由選擇。

當考慮如何在公司内部落地 dapr 時,我們提出了兩種方案,如上圖所示:

1.替換:廢棄掉現在的 MOSN,用 dapr 進行替換,這種方案存在兩個問題:

a. dapr 雖然提供了很多分布式能力,但目前并不具備 Service Mesh 包含的豐富的服務治理能力。

b. MOSN 在公司内部已經大規模落地,并且經過了多次大促考驗,直接用 dapr 來替換 MOSN 穩定性有待驗證。

2.共存:新增一個 dapr 容器,跟 MOSN 以兩個 sidecar 的模式進行部署。這種方案同樣存在兩個問題:

a. 引入一個新的 sidecar,我們就需要考慮它配套的更新、監控、注入等等事情,運維成本飙升。

b. 多元護一個容器意味着多了一層挂掉的風險,這會降低現在的系統可用性。

同樣的,如果你目前正在使用 envoy 作為資料面,也會面臨上述問題。

是以我們希望把 Runtime 跟 Service Mesh 兩者結合起來,通過一個完整的 sidecar 進行部署,在保證穩定性、運維成本不變的前提下,最大程度複用現有的各種 Mesh 能力。此外我們還希望這部分 Runtime 能力除了跟 MOSN 結合起來之外,未來也可以跟 envoy 結合起來,解決更多場景中的問題,Layotto 就是在這樣的背景下誕生。

B、Layotto 架構

MOSN 子項目 Layotto:開啟服務網格+應用運作時新篇章

如上圖所示,Layotto 是建構在 MOSN 之上,在下層對接了各種基礎設施,向上層應用提供了統一的,具有各種各樣分布式能力的标準 API。對于接入 Layotto 的應用來說,開發者不再需要關心底層各種元件的實作差異,隻需要關注應用需要什麼樣的能力,然後調用對應能力的 API 即可,這樣可以徹底跟底層基礎設施解綁。

對應用來說,互動分為兩塊,一個是作為 gRPC Client 調用 Layotto 的标準 API,一個是作為 gRPC Server 來實作 Layotto 的回調,得利于gRPC 優秀的跨語言支援能力,應用不再需要關心通信、序列化等細節問題,進一步降低了異構技術棧的使用門檻。

除了面向應用,Layotto 也向運維平台提供了統一的接口,這些接口可以把應用跟 sidecar 的運作狀态回報給運維平台,友善 SRE 同學及時了解應用的運作狀态并針對不同狀态做出不同的舉措,該功能考慮到跟 k8s 等已有的平台內建,是以我們提供了 HTTP 協定的通路方式。

除了 Layotto 本身設計以外,項目還涉及兩塊标準化建設,首先想要制定一套語義明确,适用場景廣泛的 API 并不是一件容易的事情,為此我們跟阿裡、 dapr 社群進行了合作,希望能夠推進 Runtime API 标準化的建設,其次對于 dapr 社群已經實作的各種能力的 Components 來說,我們的原則是優先複用、其次開發,盡量不把精力浪費在已有的元件上面,重複造輪子。

最後 Layotto 目前雖然是建構在 MOSN 之上,未來我們希望 Layotto 可以跑在 envoy 上,這樣隻要應用接入了 Service Mesh,無論資料面使用的是 MOSN 還是 envoy,都可以在上面增加 Runtime能力。

C、Layotto 的移植性

MOSN 子項目 Layotto:開啟服務網格+應用運作時新篇章

如上圖所示,一旦完成 Runtime API 的标準化建設,接入 Layotto 的應用天然具備了可移植性,應用不需要任何改造就可以在私有雲以及各種公有雲上部署,并且由于使用的是标準 API,應用也可以無需任何改造就在 Layotto 跟 dapr 之間自由切換。

D、名字含義

MOSN 子項目 Layotto:開啟服務網格+應用運作時新篇章

從上面的架構圖可以看出,Layotto 項目本身是希望屏蔽基礎設施的實作細節,向上層應用統一提供各種分布式能力,這種做法就好像是在應用跟基礎設施之間加了一層抽象,是以我們借鑒了 OSI 對網絡定義七層模型的思路,希望 Layotto 可以作為第八層對應用提供服務,otto 是意大利語中8的意思,Layer otto 就是第八層的意思,簡化了一下變成了 Layotto,同時項目代号 L8,也是第八層的意思,這個代号也是設計我們項目 LOGO 時靈感的來源。

介紹完項目的整體情況,下面對其中四個主要功能的實作細節進行說明。

E、配置原語

MOSN 子項目 Layotto:開啟服務網格+應用運作時新篇章

首先是分布式系統中經常使用的配置功能,應用一般使用配置中心來做開關或者動态調整應用的運作狀态。Layotto 中配置子產品的實作包括兩部分,一個是對如何定義配置這種能力的 API 的思考,一個是具體的實作,下面逐個來看。

想要定義一個能滿足大部分實際生産訴求的配置 API 并不是一件容易的事,dapr 目前也缺失這個能力,是以我們跟阿裡以及 dapr 社群一起合作,為如何定義一版合理的配置 API 進行了激烈讨論。

目前讨論結果還沒有最終确定,是以 Layotto 是基于我們提給社群的第一版草案進行實作,下面對我們的草案進行簡要說明。

我們先定義了一般配置所需的基本元素:

  1. appId:表示配置屬于哪個應用
  2. key:配置的 key
  3. content:配置的值
  4. group:配置所屬的分組,如果一個 appId 下面的配置過多,我們可以給這些配置進行分組歸類,便于維護。

此外我們追加了兩種進階特性,用來适配更加複雜的配置使用場景:

  1. label,用于給配置打标簽,比如該配置屬于哪個環境,在進行配置查詢的時候,我們會使用 label + key 來查詢配置。
  2. tags,使用者給配置追加的一些附加資訊,如描述資訊、建立者資訊,最後修改時間等等,友善配置的管理,審計等。

對于上述定義的配置 API 的具體實作,目前支援查詢、訂閱、删除、建立、修改五種操作,其中訂閱配置變更後的推送使用的是 gRPC 的 stream 特性,而底層實作這些配置能力的元件,我們選擇了國内流行的 apollo,後面也會根據需求增加其他實作。

F、Pub/Sub 原語

MOSN 子項目 Layotto:開啟服務網格+應用運作時新篇章

對于 Pub/Sub 能力的支援,我們調研了 dapr 現在的實作,發現基本上已經可以滿足我們的需求,是以我們直接複用了 dapr 的 API 以及 components,隻是在 Layotto 裡面做了适配,這為我們節省了大量的重複勞動,我們希望跟 dapr 社群保持一種合作共建的思路,而不是重複造輪子。

其中 Pub 功能是 App 調用 Layotto 提供的 PublishEvent 接口,而 Sub 功能則是應用通過 gRPC Server 的形式實作了 ListTopicSubscriptions 跟 OnTopicEvent 兩個接口,一個用來告訴 Layotto 應用需要訂閱哪些 topic,一個用于接收 topic 變化時 Layotto 的回調事件。

dapr 對于 Pub/Sub 的定義基本滿足我們的需求,但在某些場景下仍有不足,dapr 采用了 CloudEvent 标準,是以 Pub 接口沒有傳回值,這無法滿足我們生産場景中要求 Pub 消息以後服務端傳回對應的 messageID 的需求,這一點我們已經把需求送出給了 dapr 社群,還在等待回報,考慮到社群異步協作的機制,我們可能會先社群一步增加傳回結果,然後再跟社群探讨一種更好的相容方案。

G、RPC 原語

MOSN 子項目 Layotto:開啟服務網格+應用運作時新篇章

RPC 的能力大家不會陌生,這可能是微服務架構下最最基礎的需求,對于 RPC 接口的定義,我們同樣參考了 dapr 社群的定義,發現完全可以滿足我們的需求,是以接口定義就直接複用 dapr 的,但目前 dapr 提供的 RPC 實作方案還比較薄弱,而 MOSN 經過多年疊代,能力已經非常成熟完善,是以我們大膽把 Runtime 跟 Service Mesh 兩種思路結合在一起,把 MOSN 本身作為我們實作 RPC 能力的一個 Component,這樣 Layotto 在收到 RPC 請求以後交給 MOSN 進行實際資料傳輸,這種方案可以通過 istio 動态改變路由規則,降級限流等等設定,相當于直接複用了 Service Mesh 的各種能力,這也說明 Runtime 不是要推翻 Service Mesh,而是要在此基礎上繼續向前邁一步。

具體實作細節上,為了更好的跟 MOSN 融合,我們在 RPC 的實作上面加了一層 Channel,預設支援dubbo,bolt,http 三種常見的 RPC 協定,如果仍然不能滿足使用者場景,我們還追加了 Before/After 兩種 Filter,可以讓使用者做自定義擴充,實作協定轉換等需求。

H、Actuator 原語

MOSN 子項目 Layotto:開啟服務網格+應用運作時新篇章

在實際生産環境中,除了應用所需要的各種分布式能力以外,PaaS 等運維平台往往需要了解應用的運作狀态,基于這種需求,我們抽象了一套 Actuator 接口,目前 dapr 還沒有提供這方面的能力,是以我們根據内部的需求場景進行了設計,旨在把應用在啟動期、運作期等階段各種各樣的資訊暴露出去,友善 PaaS 了解應用的運作情況。

Layotto 把暴露資訊分為兩大類:

1.Health:該子產品判斷應用目前運作狀态是否健康,比如某個強依賴的元件如果初始化失敗就需要表示為非健康狀态,而對于健康檢查的類型我們參考了 k8s,分為:

a. Readiness:表示應用啟動完成,可以開始處理請求。

b. Liveness:表示應用存活狀态,如果不存活則需要切流等。

2.Info:該子產品預期會暴露應用的一些依賴資訊出去,如應用依賴的服務,訂閱的配置等等,用于排查問題。

Health 對外暴露的健康狀态分為以下三種:

  1. INIT:表示應用還在啟動中,如果應用釋出過程中傳回該值,這個時候 PaaS 平台應該繼續等待應用完成啟動。
  2. UP:表示應用啟動正常,如果應用釋出過程中傳回該值,意味着 PasS 平台可以開始放入流量。
  3. DOWN:表示應用啟動失敗,如果應用釋出過程中傳回該值,意味着 PaaS 需要停止釋出并通知應用 owner。

到這裡關于 Layotto 目前在 Runtime 方向上的探索基本講完了,我們通過定義明确語義的 API,使用 gRPC 這種标準的互動協定解決了目前面臨的基礎設施強綁定、異構語言接入成本高兩大問題。随着未來 API 标準化的建設,一方面可以讓接入 Layotto 的應用無感覺的在各種私有雲、公有雲上面部署,另一方面也能讓應用在 Layotto,dapr 之間自由切換,提高研發效率。

目前 Serverless 領域也是百花齊放,沒有一種統一的解決方案,是以 Layotto 除了在上述 Runtime 方向上的投入以外,還在 Serverless 方向上也進行了一些嘗試,下面就嘗試方案進行介紹。

四、WebAssembly 的探索

A、WebAssembly 簡介

MOSN 子項目 Layotto:開啟服務網格+應用運作時新篇章

WebAssembly,簡稱 WASM,是一個二進制指令集,最初是跑在浏覽器上來解決 JavaScript 的性能問題,但由于它良好的安全性,隔離性以及語言無關性等優秀特性,很快人們便開始讓它跑在浏覽器之外的地方,随着 WASI 定義的出現,隻需要一個 WASM 運作時,就可以讓 WASM 檔案随處執行。

既然 WebAssembly 可以在浏覽器以外的地方運作,那麼我們是否能把它用在 Serverless 領域?目前已經有人在這方面做了一些嘗試,不過如果這種方案真的想落地的話,首先要考慮的就是如何解決運作中的 WebAssembly 對各種基礎設施的依賴問題。

B、WebAssembly 落地原理

目前 MOSN 通過內建 WASM Runtime 的方式讓 WASM 跑在 MOSN 上面,以此來滿足對 MOSN 做自定義擴充的需求。同時,Layotto 也是建構在 MOSN 之上,是以我們考慮把二者結合在一起,實作方案如下圖所示:

MOSN 子項目 Layotto:開啟服務網格+應用運作時新篇章

開發者可以使用 Go/C++/Rust 等各種各樣自己喜歡的語言來開發應用代碼,然後把它們編譯成 WASM 檔案跑在 MOSN 上面,當 WASM 形态的應用在處理請求的過程中需要依賴各種分布式能力時就可以通過本地函數調用的方式調用 Layotto 提供的标準 API,這樣直接解決了 WASM 形态應用的依賴問題。

目前 Layotto 提供了 Go 跟 Rust 版 WASM 的實作,雖然隻支援 demo 級功能,但已經足夠讓我們看到這種方案的潛在價值。

此外,WASM 社群目前還處于初期階段,有很多地方需要完善,我們也給社群送出了一些 PR共同建設,為 WASM 技術的落地添磚加瓦。

C、WebAssembly 落地展望

MOSN 子項目 Layotto:開啟服務網格+應用運作時新篇章

雖然現在 Layotto 中對 WASM 的使用還處于試驗階段,但我們希望它最終可以成為 Serverless 的一種實作形态,如上圖所示,應用通過各種程式設計語言開發,然後統一編譯成 WASM 檔案,最後跑在 Layotto+MOSN 上面,而對于應用的運維管理統一由 k8s、docker、prometheus 等産品負責。

五、社群規劃

最後來看下 Layotto 在社群的做的一些事情。

A、Layotto vs Dapr

MOSN 子項目 Layotto:開啟服務網格+應用運作時新篇章

上圖列出了 Layotto 跟 dapr 現有的能力對比,在 Layotto 的開發過程中,我們借鑒 dapr 的思路,始終以優先複用、其次開發為原則,旨在達成共建的目标,而對于正在建設或者未來要建設的能力來說,我們計劃優先在 Layotto 上落地,然後再提給社群,合并到标準 API,鑒于社群異步協作的機制,溝通成本較高,是以短期内可能 Layotto 的 API 會先于社群,但長期來看一定會統一。

B、API 共建計劃

MOSN 子項目 Layotto:開啟服務網格+應用運作時新篇章

關于如何定義一套标準的 API 以及如何讓 Layotto 可以跑在 envoy 上等等事項,我們已經在各個社群進行了深入讨論,并且以後也還會繼續推進。

C、Roadmap

MOSN 子項目 Layotto:開啟服務網格+應用運作時新篇章

Layotto 在目前主要支援 RPC、Config、Pub/Sub、Actuator 四大功能,預計在九月會把精力投入到分布式鎖、State、可觀測性上面,十二月份會支援 Layotto 插件化,也就是讓它可以跑在 envoy 上,同時希望對 WebAssembly 的探索會有進一步的産出。

D、正式開源

MOSN 子項目 Layotto:開啟服務網格+應用運作時新篇章

前面詳細介紹了 Layotto 項目,最重要的還是該項目今天作為 MOSN 的子項目正式開源,我們提供了詳細的文檔以及 demo 示例友善大家快速上手體驗。

對于 API 标準化的建設是一件需要長期推動的事情,同時标準化意味着不是滿足一兩種場景,而是盡可能的适配大多數使用場景,為此我們希望更多的人可以參與到 Layotto 項目中,描述你的使用場景,讨論 API 的定義方案,一起送出給社群,最終達成 Write once, Run anywhere 的終極目标!

MOSN 子項目 Layotto:開啟服務網格+應用運作時新篇章

繼續閱讀