美團(tuán)分布式服務(wù)治理框架OCTO之二:Mesh化
寫在前面
前面的文章主要介紹了美團(tuán)Octo服務(wù)治理框架,隨著云原生的崛起,大量服務(wù)治理體系普遍“云原生”化,而Mesh則是云原生中非常重要的一個(gè)流派,今天我們看下美團(tuán)的Octo是如何一步步的Mesh化的。
Mesh化
經(jīng)過一整套服務(wù)治理能力的升級,原有Octo已經(jīng)支持了,包括set化、鏈路級復(fù)雜路由、全鏈路壓測、鑒權(quán)加密、限流熔斷等治理能力。
但整個(gè)治理體系仍存在一些痛點(diǎn)及挑戰(zhàn):
多語言支持不友好:每一個(gè)語言搞一套治理體系不現(xiàn)實(shí)
中間件和業(yè)務(wù)綁定在一起,彼此制約迭代:原有的一些治理能力是通過入侵業(yè)務(wù)代碼實(shí)現(xiàn)的,比如filter、api、sdk集成等,只是做到了邏輯隔離,未做到物理上的隔離。一般來說核心的治理能力主要由通信框架承載,如果沒有更進(jìn)一步的隔離(如物理隔離),那中間件引入的bug就需要所有業(yè)務(wù)配合升級,對業(yè)務(wù)研發(fā)效率造成傷害
治理決策比較分散:每個(gè)節(jié)點(diǎn)根據(jù)自己的狀態(tài)進(jìn)行決策,無法與其他節(jié)點(diǎn)協(xié)同仲裁
針對于以上問題,Octo升級到2.0架構(gòu),引入了Mesh概念。
Mesh模式下,為每個(gè)業(yè)務(wù)實(shí)例部署一個(gè)Sidecar代理,所有進(jìn)出應(yīng)用的業(yè)務(wù)流量統(tǒng)一由Sidecar承載,同時(shí)服務(wù)治理的工作也由Sidecar執(zhí)行,所有的Sidecar由統(tǒng)一的中心化大腦控制面進(jìn)行全局管控。
做好Mesh化升級,怎么解決上面的痛點(diǎn)的呢:
Service Mesh 模式下,各語言的通信框架一般僅負(fù)責(zé)編解碼,而編解碼的邏輯往往是不變的。核心的治理功能(如路由、限流等)主要由 Sidecar 代理和控制大腦協(xié)同完成,從而實(shí)現(xiàn)一套治理體系,所有語言通用。
中間件易變的邏輯盡量下沉到 Sidecar 和控制大腦中,后續(xù)升級中間件基本不需要業(yè)務(wù)配合。SDK 主要包含很輕薄且不易變的邏輯,從而實(shí)現(xiàn)了業(yè)務(wù)和中間件的解耦。
新融入的異構(gòu)技術(shù)體系可以通過輕薄的 SDK 接入美團(tuán)治理體系(技術(shù)體系難兼容,本質(zhì)是它們各自有獨(dú)立的運(yùn)行規(guī)范,在 Service Mesh 模式下運(yùn)行規(guī)范核心內(nèi)容就是控制面和Sidecar),目前美團(tuán)線上也有這樣的案例。
控制大腦集中掌控了所有節(jié)點(diǎn)的信息,進(jìn)而可以做一些全局最優(yōu)的決策,比如服務(wù)預(yù)熱、根據(jù)負(fù)載動(dòng)態(tài)調(diào)整路由等能力。
總結(jié)起來:盡量將治理能力與業(yè)務(wù)邏輯剝離開來,通過輕量級的SDK與業(yè)務(wù)邏輯耦合,但這一部分設(shè)計(jì)需要盡量輕薄,更多治理能力下沉到SideCar與控制大腦。
整體架構(gòu)
Octo2.0整體架構(gòu)如下:

協(xié)作系統(tǒng)包括服務(wù)治理系統(tǒng)、鑒權(quán)服務(wù)、配置中心、限流服務(wù)等,這些原有服務(wù)治理能力在Mesh架構(gòu)下是可復(fù)用的,無需重復(fù)開發(fā)。
Mesh的技術(shù)選型
美團(tuán)的Mesh改造起步于2018年底,當(dāng)時(shí)的一個(gè)核心問題是整體方案的考量應(yīng)該關(guān)注于哪幾個(gè)方面。
啟動(dòng)計(jì)劃階段時(shí),有了一些非常明確的關(guān)注點(diǎn):
Octo體系經(jīng)過五年的迭代,形成了一系列的標(biāo)準(zhǔn)與規(guī)范,進(jìn)行Mesh改造治理體系升級范圍會(huì)非常大,在確保技術(shù)方案可以落地的同事,也要屏蔽技術(shù)升級對于業(yè)務(wù)改動(dòng)
治理能力不能減弱,在保障對齊的基礎(chǔ)上逐漸提供更精細(xì)、更易用的運(yùn)營能力
可以應(yīng)對超大規(guī)模的挑戰(zhàn),技術(shù)方案需要確保支撐當(dāng)前兩級甚至N倍的增量,系統(tǒng)自身不能成為整個(gè)治理體系的瓶頸
盡量與社區(qū)保持親和,一定程度上和社區(qū)協(xié)同演進(jìn)
于是產(chǎn)出了如下的技術(shù)選型方案:

于是選擇了一種數(shù)據(jù)層面基于Envoy二次開發(fā),控制碼自研的整體選型與方案。
數(shù)據(jù)面方面,當(dāng)時(shí) Envoy 有機(jī)會(huì)成為數(shù)據(jù)面的事實(shí)標(biāo)準(zhǔn),同時(shí) Filter 模式及 xDS 的設(shè)計(jì)對擴(kuò)展比較友好,未來功能的豐富、性能優(yōu)化也與標(biāo)準(zhǔn)關(guān)系較弱。
控制面自研為主的決策需要考量的內(nèi)容就比較復(fù)雜,總體而言需要考慮如下幾個(gè)方面:
美團(tuán)容器化主要采用富容器的模式,這種模式下強(qiáng)行與 Istio 及 Kubernetes 的數(shù)據(jù)模型匹配改造成本極高,同時(shí) Istio API也尚未確定。
Istio 在集群規(guī)模變大時(shí)較容易出現(xiàn)性能問題,無法支撐美團(tuán)數(shù)萬應(yīng)用、數(shù)十萬節(jié)點(diǎn)的的體量,同時(shí)數(shù)十萬節(jié)點(diǎn)規(guī)模的 Kubernetes 集群也需要持續(xù)優(yōu)化探索。
Istio 的功能無法滿足 OCTO 復(fù)雜精細(xì)的治理需求,如流量錄制回放壓測、更復(fù)雜的路由策略等。
項(xiàng)目啟動(dòng)時(shí)非容器應(yīng)用占比較高,技術(shù)方案需要兼容存量非容器應(yīng)用。
整體Mesh方案如下:

這張圖展示了 OCTO Mesh 的整體架構(gòu)。從下至上來看,邏輯上分為業(yè)務(wù)進(jìn)程及通信框架 SDK 層、數(shù)據(jù)平面層、控制平面層、治理體系協(xié)作的所有周邊生態(tài)層。
先來重點(diǎn)介紹下業(yè)務(wù)進(jìn)程及SDK層、數(shù)據(jù)平面層:
OCTO Proxy (數(shù)據(jù)面Sidecar代理內(nèi)部叫OCTO Proxy)與業(yè)務(wù)進(jìn)程采用1對1的方式部署。
OCTO Proxy 與業(yè)務(wù)進(jìn)程采用 UNIX Domain Socket 做進(jìn)程間通信(這里沒有選擇使用 Istio 默認(rèn)的 iptables 流量劫持,主要考慮美團(tuán)內(nèi)部基本是使用的統(tǒng)一化私有協(xié)議通信,富容器模式?jīng)]有用 Kubernetes 的命名服務(wù)模型,iptables 管理起來會(huì)很復(fù)雜,而 iptables 復(fù)雜后性能會(huì)出現(xiàn)較高的損耗。);OCTO Proxy 間跨節(jié)點(diǎn)采用 TCP 通信,采用和進(jìn)程間同樣的協(xié)議,保證了客戶端和服務(wù)端具備獨(dú)立升級的能力。
為了提升效率同時(shí)減少人為錯(cuò)誤,我們獨(dú)立建設(shè)了 OCTO Proxy 管理系統(tǒng),部署在每個(gè)實(shí)例上的 LEGO Agent 負(fù)責(zé) OCTO Proxy 的保活和熱升級,類似于 Istio 的 Pilot Agent,這種方式可以將人工干預(yù)降到較低,提升運(yùn)維效率。
數(shù)據(jù)面與控制面通過雙向流式通信。路由部分交互方式是增強(qiáng)語義的 xDS,增強(qiáng)語義是因?yàn)楫?dāng)前的 xDS 無法滿足美團(tuán)更復(fù)雜的路由需求;除路由外,該通道承載著眾多的治理功能的指令及配置下發(fā),我們設(shè)計(jì)了一系列的自定義協(xié)議。

控制面(美團(tuán)內(nèi)部名稱為Adcore)自研為主,整體分為:Adcore Pilot、Adcore Dispatcher、集中式健康檢查系統(tǒng)、節(jié)點(diǎn)管理模塊、監(jiān)控預(yù)警模塊。此外獨(dú)立建設(shè)了統(tǒng)一元數(shù)據(jù)管理及 Mesh 體系內(nèi)的服務(wù)注冊發(fā)現(xiàn)系統(tǒng) Meta Server 模塊。
每個(gè)模塊的具體職責(zé)如下:
Adcore Pilot 是個(gè)獨(dú)立集群,模塊承載著大部分核心治理功能的管控,相當(dāng)于整個(gè)系統(tǒng)的大腦,也是直接與數(shù)據(jù)面交互的模塊。
Adcore Dispatcher 也是獨(dú)立集群,該模塊是供治理體系協(xié)作的眾多子系統(tǒng)便捷接入 Mesh 體系的接入中心。
不同于 Envoy 的 P2P 節(jié)點(diǎn)健康檢查模式,OCTO Mesh 體系使用的是集中式健康檢查。
控制面節(jié)點(diǎn)管理系統(tǒng)負(fù)責(zé)采集每個(gè)節(jié)點(diǎn)的運(yùn)行時(shí)信息,并根據(jù)節(jié)點(diǎn)的狀態(tài)做全局性的最優(yōu)治理的決策和執(zhí)行。
監(jiān)控預(yù)警系統(tǒng)是保障 Mesh 自身穩(wěn)定性而建設(shè)的模塊,實(shí)現(xiàn)了自身的可觀測性,當(dāng)出現(xiàn)故障時(shí)能快速定位,同時(shí)也會(huì)對整個(gè)系統(tǒng)做實(shí)時(shí)巡檢。
與Istio 基于 Kubernetes 來做尋址和元數(shù)據(jù)管理不同,OCTO Mesh 由獨(dú)立的 Meta Server 負(fù)責(zé) Mesh 自身眾多元信息的管理和命名服務(wù)。
實(shí)現(xiàn)原理
我們看下核心Mesh架構(gòu)實(shí)現(xiàn)原理。
流量劫持
Octo并未采用Istio的原生方案,而是使用iptables對進(jìn)出POD的流量進(jìn)行劫持:
iptables自身存在性能損失大、管控性差的問題:
iptables在內(nèi)核對于包的處理過程中定義了五個(gè)“hook point”,每個(gè)“hook point”各對應(yīng)到一組規(guī)則鏈,outbond流量將兩次穿越協(xié)議棧并且經(jīng)過這5組規(guī)則鏈匹配,在大并發(fā)場景下會(huì)損失轉(zhuǎn)發(fā)性能。 iptables全局生效,不能顯式地禁止相關(guān)規(guī)則的修改,沒有相關(guān)ACL機(jī)制,可管控性比較差。 在美團(tuán)現(xiàn)有的環(huán)境下,使用iptables存在以下幾個(gè)問題:
HULK容器為富容器形態(tài),業(yè)務(wù)進(jìn)程和其他所有基礎(chǔ)組件都處于同一容器中,這些組件使用了各種各樣的端口,使用iptables容易造成誤攔截。 美團(tuán)現(xiàn)在存在物理機(jī)、虛擬機(jī)、容器等多個(gè)業(yè)務(wù)運(yùn)行場景,基于iptables的流量劫持方案在適配這些場景時(shí)復(fù)雜度較高。
鑒于以上兩個(gè)問題,最終采用了Unix Domain Socket直連方式,實(shí)現(xiàn)了業(yè)務(wù)進(jìn)程和Octo Proxy進(jìn)程之間的流量轉(zhuǎn)發(fā)。
服務(wù)消費(fèi)者一方,業(yè)務(wù)進(jìn)程通過輕量級的Mesh SDK和Octo Proxy監(jiān)聽的UDS地址建立連接。
服務(wù)提供者一方,Octo Proxy代替業(yè)務(wù)進(jìn)程監(jiān)聽在TCP端口上,業(yè)務(wù)進(jìn)程則監(jiān)聽在制定的UDF地址上。
UDS相比于iptable劫持有更好的性能和更低的運(yùn)維成本,缺點(diǎn)是需要SDK。
服務(wù)訂閱
原生的Envoy的CDS、EDS請求時(shí)全量服務(wù)發(fā)現(xiàn)模式,是將系統(tǒng)中所有的服務(wù)列表都請求到數(shù)據(jù)面來進(jìn)行處理。
由于大規(guī)模服務(wù)集群的服務(wù)數(shù)量太多,而需要的服務(wù)信息是少數(shù)的,所以需要改造成按需獲取服務(wù)的發(fā)現(xiàn)模式,只需要請求要訪問的后端服務(wù)節(jié)點(diǎn)列表就可以了。

流程如下:
業(yè)務(wù)進(jìn)程啟動(dòng)之后,通過http方式向Octo proxy發(fā)起服務(wù)訂閱請求,Octo Proxy將所要請求的后端AppKey更新到Xds中,Xds在向控制面請求具體的服務(wù)資源。
為增加整個(gè)過程健壯性,降低后期運(yùn)維成本,做了一定的優(yōu)化。比如Octo Proxy的啟動(dòng)速度有可能比業(yè)務(wù)進(jìn)程啟動(dòng)慢,所以Mesh SDK中增加了請求重試的邏輯,確保請求真正可以經(jīng)由Octo Proxy發(fā)出去。
Mesh SDK和Octo Proxy之間的http請求改成了同步請求,防止pilot資源下發(fā)延遲帶來問題。
Mesh SDK的訂閱信息也會(huì)保存在本地文件中,以便在Octo Proxy重啟或更新過程中,服務(wù)的可用性。
無損熱重啟
由于業(yè)務(wù)進(jìn)程和Octo Proxy是獨(dú)立的進(jìn)程,確保Proxy進(jìn)程熱更新時(shí)可以持續(xù)提供服務(wù),對業(yè)務(wù)無損無感知就非常重要。社區(qū)的Envoy自己支持的熱重啟不夠完善,不能做到完全的無損流量。
我們看下在短連接和長連接兩種情況下Octo Proxy重啟可能造成的流量損耗問題。

在短連接場景下,所有的新連接會(huì)在Octo Proxy New上創(chuàng)建,Octo Proxy Old上已有的連接會(huì)在響應(yīng)到來后主動(dòng)斷開。Octo Proxy Old的所有短連接逐漸斷開,當(dāng)所有連接斷開之后,Octo Proxy Old主動(dòng)退出,Octo Proxy New繼續(xù)工作,整個(gè)過程中流量是無損的。
在長連接場景下,SDK和Octo Proxy Old之間維持一個(gè)長連接斷不開,并持續(xù)使用這個(gè)連接發(fā)送請求。Ocot Proxy Old進(jìn)程最終退出時(shí),該鏈接才被迫斷開,這時(shí)可能有部分請求還未返回,導(dǎo)致Client端請求超時(shí),因此Envoy的熱重啟對長連接場景支持的不完美。
為實(shí)現(xiàn)基礎(chǔ)組件更新過程不對業(yè)務(wù)流量造成損耗,業(yè)界的主要方式是滾動(dòng)發(fā)布。也就是,不是直接全部更新,而是一部分一部分的更新,滾動(dòng)的承接流量+主動(dòng)斷開連接。
服務(wù)節(jié)點(diǎn)分批停止服務(wù),執(zhí)行更新,然后重啟,投入使用,直到集群中所有實(shí)例都更新為最新版本。這個(gè)過程中會(huì)主動(dòng)摘到業(yè)務(wù)流量,保證升級過程中業(yè)務(wù)流量不丟失。

美團(tuán)的方案是進(jìn)行角色劃分,將業(yè)務(wù)服務(wù)分為兩個(gè)角色:
對外提供服務(wù)的server端;
發(fā)起請求調(diào)用的client端;
client端octo proxy熱更新:
octo proxy old進(jìn)入重啟狀態(tài),對后續(xù)的請求直接返回“熱更新”標(biāo)志的響應(yīng)協(xié)議,client sdk在收到“熱更新”的協(xié)議標(biāo)識(shí)之后,主動(dòng)切換連接進(jìn)行重試。然后斷開sdk上和octo proxy old之間的長連接。

通過client sdk和octo proxy之間的交互配合,可以實(shí)現(xiàn)client在octo proxy升級過程中的流量安全。
server端coto proxy熱更新:
server端的octo proxy在熱更新開始后,主動(dòng)向client側(cè)的octo proxy發(fā)送proxy restart消息,也就是要求client側(cè)的octo proxy主動(dòng)切換新連接,避免當(dāng)前client側(cè)octo proxy持有的舊鏈接被強(qiáng)制關(guān)閉,導(dǎo)致請求失敗。
client側(cè)octo proxy收到“主動(dòng)切換新連接”的請求后,應(yīng)及時(shí)從可用連接池中清除老的長連接。

數(shù)據(jù)面運(yùn)維
在云原生環(huán)境下,Envoy運(yùn)行在標(biāo)準(zhǔn)的K8s Pod中,通常會(huì)獨(dú)立出一個(gè)Sidecar容器,這樣可以借助K8s的能力實(shí)現(xiàn)對Envoy Sidecar容器的管理,比如容器注入、健康檢查、滾動(dòng)升級、資源限制等。
美團(tuán)內(nèi)部的容器運(yùn)行時(shí)模式為:單容器模式。就是在一個(gè)pod內(nèi)只包含一個(gè)容器。
由于業(yè)務(wù)進(jìn)程和所有基礎(chǔ)組件都運(yùn)行在一個(gè)容器中,所以只能采用進(jìn)程粒度的管理措施,無法做到容器粒度的管理。

Lego Agent支持了對Octo Proxy熱更新的感知,還負(fù)責(zé)對Octo Proxy進(jìn)行健康檢查、故障狀態(tài)重啟、監(jiān)控信息上報(bào)和版本發(fā)布等。相對于原生k8s的容器重啟方式,進(jìn)程粒度重啟會(huì)更快。
擴(kuò)展性及完善的運(yùn)維體系
關(guān)鍵設(shè)計(jì)
大規(guī)模治理體系 Mesh 化建設(shè)成功落地的關(guān)鍵點(diǎn)有:
系統(tǒng)水平擴(kuò)展能力方面,可以支撐數(shù)萬應(yīng)用/百萬級節(jié)點(diǎn)的治理。
功能擴(kuò)展性方面,可以支持各類異構(gòu)治理子系統(tǒng)融合打通。
能應(yīng)對 Mesh 化改造后鏈路復(fù)雜的可用性、可靠性要求。
具備成熟完善的 Mesh 運(yùn)維體系。
圍繞這四點(diǎn),便可以在系統(tǒng)能力、治理能力、穩(wěn)定性、運(yùn)營效率方面支撐美團(tuán)當(dāng)前多倍體量的新架構(gòu)落地。

對于社區(qū) Istio 方案,要想實(shí)現(xiàn)超大規(guī)模應(yīng)用集群落地,需要完成較多的技術(shù)改造。
因?yàn)?Istio 水平擴(kuò)展能力相對薄弱,內(nèi)部冗余操作多,整體穩(wěn)定性較為薄弱。
解決思路如下:
控制面每個(gè)節(jié)點(diǎn)并不承載所有治理數(shù)據(jù),系統(tǒng)整體做水平擴(kuò)展。
在此基礎(chǔ)上提升每個(gè)實(shí)例的整體吞吐量和性能。
當(dāng)出現(xiàn)機(jī)房斷網(wǎng)等異常情況時(shí),可以應(yīng)對瞬時(shí)流量驟增的能力。
只做必要的 P2P 模式健康檢查,配合集中式健康檢查進(jìn)行百萬級節(jié)點(diǎn)管理。

按需加載和數(shù)據(jù)分片主要由 Adcore Pilot、Meta Server 實(shí)現(xiàn)。
Pilot 的邏輯是管理每個(gè)數(shù)據(jù)面會(huì)話的全生命周期、會(huì)話的創(chuàng)建、交互及銷毀等一系列動(dòng)作及流程;
維護(hù)數(shù)據(jù)最新的一致性快照,對下將資源更新同步處理,對上響應(yīng)各平臺(tái)的數(shù)據(jù)變更通知,將存在關(guān)聯(lián)關(guān)系的一組數(shù)據(jù)做快照緩存。
控制面每個(gè) Pilot 節(jié)點(diǎn)并不會(huì)把整個(gè)注冊中心及其他數(shù)據(jù)都加載進(jìn)來,而是按需加載自己管控的 Sidecar 所需要的相關(guān)治理數(shù)據(jù)。
同一個(gè)應(yīng)用的所有 OCTO Proxy 由同一個(gè)Pilot 實(shí)例管控,Meta Server,自己實(shí)現(xiàn)控制面機(jī)器服務(wù)發(fā)現(xiàn)和精細(xì)化控制路由規(guī)則,從而在應(yīng)用層面實(shí)現(xiàn)了數(shù)據(jù)分片。

Meta Server 管控每個(gè)Pilot節(jié)點(diǎn)和OCTO Proxy的歸屬關(guān)系。
當(dāng) Pilot 實(shí)例啟動(dòng)后會(huì)注冊到 Meta Server,此后定時(shí)發(fā)送心跳進(jìn)行續(xù)租,長時(shí)間心跳異常會(huì)自動(dòng)剔除。
Meta Server 內(nèi)部有一致性哈希策略,會(huì)綜合節(jié)點(diǎn)的應(yīng)用、機(jī)房、負(fù)載等信息進(jìn)行分組。當(dāng)一個(gè) Pilot 節(jié)點(diǎn)異?;虬l(fā)布時(shí),該 Pilot 的 OCTO Proxy 都會(huì)有規(guī)律的連接到接替節(jié)點(diǎn),而不會(huì)全局隨機(jī)連接對后端注冊中心造成風(fēng)暴。
當(dāng)異?;虬l(fā)布后的節(jié)點(diǎn)恢復(fù)后,劃分出去的 OCTO Proxy 又會(huì)有規(guī)則的重新歸屬當(dāng)前 Pilot 實(shí)例管理。
對于關(guān)注節(jié)點(diǎn)特別多的應(yīng)用 OCTO Proxy,也可以獨(dú)立部署 Pilot,通過 Meta Server 統(tǒng)一進(jìn)行路由管理。

穩(wěn)定性保障設(shè)計(jì)

圍繞控制故障影響范圍、異常實(shí)時(shí)自愈、可實(shí)時(shí)回滾、柔性可用、提升自身可觀測性及回歸能力進(jìn)行建設(shè)。

命名服務(wù)與注冊中心打通
Mesh體系的命名服務(wù)需要 Pilot 與注冊中心打通。
采用ZK實(shí)現(xiàn)的方式是每個(gè) OCTO Proxy 與 Pilot 建立會(huì)話時(shí),作為客戶端角色會(huì)向注冊中心訂閱自身所關(guān)注的服務(wù)端變更監(jiān)聽器,如果這個(gè)服務(wù)需要訪問100個(gè)應(yīng)用,則至少需要注冊100個(gè) Watcher 。
如果存在1000個(gè)實(shí)例同時(shí)運(yùn)行,就會(huì)注冊 100 x 1000 = 100000 個(gè) Watcher。還有很多應(yīng)用有相同的關(guān)注的對端節(jié)點(diǎn),造成大量的冗余監(jiān)聽。
規(guī)模較大后,網(wǎng)絡(luò)抖動(dòng)或業(yè)務(wù)集中發(fā)布時(shí),很容易引發(fā)風(fēng)暴效應(yīng)把控制面和后端的注冊中心打掛。
針對這個(gè)問題,可以采用分層訂閱方式。
就是每個(gè) OCTO Proxy 的會(huì)話并不直接和注冊中心或其他的發(fā)布訂閱系統(tǒng)交互,而是將變更的通知全部由 Snapshot 快照層管理。
Snapshot 內(nèi)部又劃分為3層:
Data Cache 層對接并緩存注冊中心及其他系統(tǒng)的原始數(shù)據(jù),粒度是應(yīng)用;
Node Snapshot 層則是保留經(jīng)過計(jì)算的節(jié)點(diǎn)粒度的數(shù)據(jù);
Ability Manager 層內(nèi)部會(huì)做索引和映射的管理,當(dāng)注冊中心存在節(jié)點(diǎn)狀態(tài)變更時(shí),會(huì)通過索引將變更推送給關(guān)注變更的 OCTO Proxy;
回到剛才的場景,隔離一層后1000個(gè)節(jié)點(diǎn)僅需注冊100個(gè) Watcher,一個(gè) Watcher 變更后僅會(huì)有一條變更信息到 Data Cache 層,再根據(jù)索引向1000個(gè) OCTO Proxy 通知,從而極大的降低了注冊中心及 Pilot 的負(fù)載。

Snapshot 層除了減少不必要交互提升性能外,還會(huì)將計(jì)算后的數(shù)據(jù)格式化緩存下來,這樣瞬時(shí)大量的請求會(huì)在快照層被緩存擋住。
預(yù)加載的主要目的是提升服務(wù)冷啟動(dòng)性能。
在 Pilot 節(jié)點(diǎn)中加載好最新的數(shù)據(jù),當(dāng)業(yè)務(wù)進(jìn)程啟動(dòng)時(shí),Proxy 就可以立即從 Snapshot 中獲取到數(shù)據(jù),避免了首次訪問慢的問題。

Istio 默認(rèn)每個(gè) Envoy 代理對整個(gè)集群中所有其余 Envoy 進(jìn)行 P2P 健康檢測。
當(dāng)集群有N個(gè)節(jié)點(diǎn)時(shí),一個(gè)檢測周期內(nèi)就需要做N的平方次檢測,另外當(dāng)集群規(guī)模變大時(shí),所有節(jié)點(diǎn)的負(fù)載就會(huì)相應(yīng)提高,這都將成為擴(kuò)展部署的極大障礙。
美團(tuán)采用了集中式的健康檢查方式,同時(shí)配合必要的P2P檢測:
由中心服務(wù) Scanner 監(jiān)測所有節(jié)點(diǎn)的狀態(tài),當(dāng) Scanner 主動(dòng)檢測到節(jié)點(diǎn)異常或 Pilot 感知連接變化通知 Scanner 掃描確認(rèn)節(jié)點(diǎn)異常時(shí), Pilot 立刻通過 eDS 更新節(jié)點(diǎn)狀態(tài)給 Proxy,這種模式下檢測周期內(nèi)僅需要檢測 N 次。(Google 的Traffic Director 也采用了類似的設(shè)計(jì),但大規(guī)模使用需要一些技巧:第一個(gè)是為了避免機(jī)房自治的影響而選擇了同機(jī)房檢測方式,第二個(gè)是為了減少中心檢測機(jī)器因自己 GC 或網(wǎng)絡(luò)異常造成誤判,而采用了Double Check 的機(jī)制)。
除了集中健康檢查,還會(huì)對頻繁失敗的對端進(jìn)行心跳探測,根據(jù)探測結(jié)果進(jìn)行摘除操作,提升成功率。
異構(gòu)治理系統(tǒng)融合設(shè)計(jì)
Istio 和 Kubernetes 將所有的數(shù)據(jù)存儲(chǔ)、發(fā)布訂閱機(jī)制都依賴 Etcd 統(tǒng)一實(shí)現(xiàn),但美團(tuán)的10余個(gè)治理子系統(tǒng)功能各異、存儲(chǔ)各異、發(fā)布訂閱模式各異,呈現(xiàn)出明顯的異構(gòu)特征,如果接入一個(gè)功能就需要平臺(tái)進(jìn)行存儲(chǔ)或其他大規(guī)模改造,這樣是完全不可行的。
一個(gè)思路是由一個(gè)模塊來解耦治理子系統(tǒng)與 Pilot ,這個(gè)模塊承載所有的變更并將這個(gè)變更下發(fā)給 Pilot。
獨(dú)立的統(tǒng)一接入中心,屏蔽所有異構(gòu)系統(tǒng)的存儲(chǔ)、發(fā)布訂閱機(jī)制;
Meta Server 承擔(dān)實(shí)時(shí)分片規(guī)則的元數(shù)據(jù)管理;

執(zhí)行機(jī)制如上圖:
各系統(tǒng)變更時(shí)使用客戶端將變更通知推送到消息隊(duì)列,只推送變更但不包含具體值(當(dāng)Pilot接收到變更通知后,會(huì)主動(dòng)Fetch全量數(shù)據(jù),這種方式一方面確保Mafka的消息足夠小,另一方面多個(gè)變更不需要在隊(duì)列中保序解決版本沖突問題。);
Adcore Dispatcher 消費(fèi)信息,并根據(jù)索引將變更推送到關(guān)注的 Pilot 機(jī)器,當(dāng) Pilot 管控的 Proxy 變更時(shí)會(huì)同步給 Meta Server,Meta Server 實(shí)時(shí)將索引關(guān)系更新并同步給Dispatcher;
為了解決 Pilot 與應(yīng)用的映射變更間隙出現(xiàn)消息丟失,Dispatcher 使用回溯檢驗(yàn)變更丟失的模式進(jìn)行補(bǔ)償,以提升系統(tǒng)的可靠性;
運(yùn)維體系設(shè)計(jì)

操作流程如下:
運(yùn)維人員在 LEGO 平臺(tái)發(fā)版,確定發(fā)版版本;
新版本資源內(nèi)容上傳至資源倉庫,并更新規(guī)則及發(fā)版范圍至 DB;
升級指令下發(fā)至所要發(fā)布的范圍;
收到發(fā)版命令機(jī)器的 LEGO Agent 去資源倉庫拉取要更新的版本(如有失敗,會(huì)有主動(dòng) Poll 機(jī)制保證升級成功);
新版本下載成功后,由 LEGO Agent 啟動(dòng)新版的 OCTO Proxy;
總結(jié)
美團(tuán)的Mesh方案已經(jīng)看不懂了,看不懂只能后續(xù)再熟悉Mesh一些回頭再看。
整體看來,美團(tuán)這套Mesh演進(jìn)方案對大家還是非常有借鑒意義的,因?yàn)樯螹esh勢必是已經(jīng)到了一定的治理規(guī)模,這里會(huì)遇到一個(gè)很重要的問題是,如何將Mesh的治理能力有機(jī)的集成到已經(jīng)成熟的某套治理能力下,比如微服務(wù)治理體系。
所以這種面向未來新的治理體系來了之后,更多的問題是如何借鑒新模式方案方式去優(yōu)化我們的系統(tǒng)中,簡單說是要個(gè)“神”,而不必是“形”,比如你可以按需替換掉Mesh里面某些模塊、組件等,以我們成熟的能力去承接。
