Service Mesh 实践指南:从单体应用到 Service Mesh 的曲折历程
技術(shù)支撐著業(yè)務(wù)高歌猛進(jìn),業(yè)務(wù)增長(zhǎng)反過來又驅(qū)動(dòng)著技術(shù)不斷向前演化,這是每個(gè)互聯(lián)網(wǎng)公司發(fā)展過程中不變的旋律。作為全國(guó)最大社交媒體網(wǎng)站的微博更是如此。
從 2009 年上線至今,微博架構(gòu)經(jīng)歷了從最初的單體應(yīng)用到后面的 RPC 服務(wù)化、容器化、混合云架構(gòu)以及現(xiàn)在的跨語言服務(wù)化和 Service Mesh 等諸多階段,架構(gòu)演變支撐著微博業(yè)務(wù)的一次次華麗轉(zhuǎn)身,也見證了微博的飛速成長(zhǎng)。
那么,微博架構(gòu)是如何從一開始的單體應(yīng)用一步步成長(zhǎng)為今天的龐大規(guī)模?作為國(guó)內(nèi)最早落地 Service Mesh 的公司,微博為什么要選擇做 Service Mesh,具體又是如何做的?這是本系列文章將試圖回答的問題。
在第一篇文章中,我會(huì)結(jié)合微博架構(gòu)演進(jìn)的歷程向你展示當(dāng)前微博架構(gòu)的整體概貌。從第二篇文章開始,我將聚焦于微博在 Service Mesh 方面的具體落地實(shí)踐,為你詳細(xì)講解微博自研的服務(wù)網(wǎng)格 WeiboMesh 從 0 到 1 的成長(zhǎng)歷程。當(dāng)然,其中也會(huì)有我自己對(duì)架構(gòu)演進(jìn)的一些思考。
下面,我們進(jìn)入正題。
在業(yè)務(wù)發(fā)展的每個(gè)階段,面臨的問題都不盡相同,而問題又有各種優(yōu)先級(jí),這就難免為了解決某些較為迫切的問題而引入一些當(dāng)時(shí)不 Care 的問題,這也是日常架構(gòu)演化過程中難以避免的魔咒。
魚和熊掌不可兼得,所以架構(gòu)演化的真諦就在于各種方案評(píng)估中的利弊權(quán)衡,在以業(yè)務(wù)為重的前提下進(jìn)行正向演化。
那么,微博各個(gè)發(fā)展時(shí)期的架構(gòu)又是如何演化的呢?
業(yè)務(wù)初期:單體架構(gòu)
微博發(fā)展初期,用戶規(guī)模高速增長(zhǎng),伴隨而來的還有不斷涌現(xiàn)的新業(yè)務(wù),因?yàn)槟悴恢滥膫€(gè)今天還名不見經(jīng)傳的業(yè)務(wù)明天就會(huì)搖身一變成為備受矚目的核心業(yè)務(wù),大家就像在白紙上瘋狂試錯(cuò)。這個(gè)時(shí)候,快速開發(fā)上線才是當(dāng)務(wù)之急。
為了達(dá)成這個(gè)目標(biāo),我們對(duì)整個(gè)系統(tǒng)做了優(yōu)良的模塊化設(shè)計(jì),每個(gè)業(yè)務(wù)作為一個(gè)獨(dú)立的模塊,保障業(yè)務(wù)能獨(dú)立開發(fā)、發(fā)布并快速上線。
同時(shí)我們自研了容器框架 Cedrus,并在接入層實(shí)現(xiàn)了一些通用的邏輯,比如提供統(tǒng)一的認(rèn)證、頻次控制、黑白名單、降級(jí)開關(guān)、配置服務(wù)等功能。平臺(tái)服務(wù)內(nèi)部則通過 Jar 包的方式依賴調(diào)用,對(duì)外暴露 API 接口。
在部署方面,我們采用大服務(wù)池整體部署的方案,這樣一來我們可以更合理地利用資源,避免為每個(gè)項(xiàng)目每個(gè)模塊單獨(dú)配置資源。
這種單體架構(gòu)的好處在于資源利用更合理,通過 Jar 包應(yīng)用來完成的本地服務(wù)調(diào)用不僅更直接,性能也更高,模塊之間開發(fā)也相互獨(dú)立,很多通用的前置邏輯被統(tǒng)一剝離出來后,業(yè)務(wù)的同學(xué)只需要關(guān)注自己的邏輯實(shí)現(xiàn)就可以了。當(dāng)然,單體架構(gòu)的缺點(diǎn)也很突出,最主要的就是耦合。項(xiàng)目之間強(qiáng)耦合帶來了一系列問題,比如升級(jí)困難,回歸測(cè)試非常難做,以及隨著業(yè)務(wù)模塊的增多,模塊之間的依賴解決困難等問題,此外還有各種 Jar 包沖突,越往后功能越加臃腫,業(yè)務(wù)變更十分吃力。這時(shí)候,就必須考慮做拆分了。
?
業(yè)務(wù)穩(wěn)定期:服務(wù)化改造
要對(duì)當(dāng)時(shí)規(guī)模已經(jīng)十分龐大的微博平臺(tái)做拆分是一件極具挑戰(zhàn)的事情,好在當(dāng)時(shí)微博業(yè)務(wù)的發(fā)展已進(jìn)入穩(wěn)定期。這就是我之前所說的,在每個(gè)發(fā)展階段我們所面臨的問題都不盡相同,如果說前期大規(guī)模的單體架構(gòu)是為了解決當(dāng)時(shí)業(yè)務(wù)的溫飽問題,那么以系統(tǒng)拆分為出發(fā)點(diǎn)的服務(wù)化改造就是要做到不但要溫飽,還要吃得好。
我們希望通過架構(gòu)改造來達(dá)到保證服務(wù)高可用的同時(shí)實(shí)現(xiàn)業(yè)務(wù)解耦的目的,以便更好地支撐業(yè)務(wù)發(fā)展。如何做到這一點(diǎn)?
我們主要從業(yè)務(wù)模塊拆分方面來考慮,基于我們之前模塊化的單體應(yīng)用架構(gòu),按業(yè)務(wù)模塊拆分是最自然也最容易想到的方案。我們只需要把以往基于 Jar 包依賴的大一統(tǒng)平臺(tái)按照業(yè)務(wù)模塊做拆分然后獨(dú)立部署,即可達(dá)到業(yè)務(wù)解耦的目的。
?
RPC 服務(wù)化
但是拆分之后服務(wù)之間依賴的問題如何解決?我們當(dāng)時(shí)面臨兩種選擇,一種是提供 HTTP 的 RESTful 接口,一種是使用 RPC 提供遠(yuǎn)端過程調(diào)用。
RESTful 接口的好處在于 HTTP 是明文協(xié)議,開發(fā)調(diào)試比較方便,RESTful 接口描述也足夠簡(jiǎn)單。但缺點(diǎn)也很突出,HTTP 協(xié)議本身比較臃腫,我們內(nèi)部服務(wù)的依賴主要解決數(shù)據(jù)可靠性傳輸?shù)膯栴},并不需要那么多無用的請(qǐng)求頭。
相比之下, RPC 具有可編程特性,可以根據(jù)微博的業(yè)務(wù)特性定制化開發(fā)。同時(shí),因?yàn)槭褂盟接袇f(xié)議,所以能大大減小每個(gè)請(qǐng)求的體量,這對(duì)內(nèi)部服務(wù)動(dòng)輒過億的依賴調(diào)用來說,能節(jié)省不少專線帶寬,同時(shí)能收獲更高的訪問性能。所以我們決定采用 RPC 的方式來解耦服務(wù)間依賴。
另外,在技術(shù)選型方面,因?yàn)?RPC 框架會(huì)是我們今后服務(wù)依賴的核心組件,所以我們特別慎重。選擇使用現(xiàn)成的開源方案還是走自研之路?這是當(dāng)時(shí)擺在我們面前的一大現(xiàn)實(shí)問題。
我們最終決定自研 RPC 框架,原因在于,如果使用開源方案,很難找到一款完全適合微博場(chǎng)景的 RPC 框架,就算找到一個(gè)差不多能滿足的,但要在線上生產(chǎn)使用,不摸個(gè)一清二楚我們也不敢上,這個(gè)熟悉的過程成本同樣不低。
而且,開源軟件的發(fā)展一般遵從于社區(qū)意志,不以微博的需求為轉(zhuǎn)移。如果到時(shí)候出現(xiàn)不得不基于微博場(chǎng)景的分叉,離社區(qū)越來越遠(yuǎn),還不如一開始就走自研的道路。所以 2013 年起我們開始了 RPC 服務(wù)化改造之路。
我們自研了微博自己的 RPC 框架 Motan,結(jié)合注冊(cè)中心,實(shí)現(xiàn)了業(yè)務(wù)的解耦和服務(wù)的高效治理。之后, Motan 經(jīng)歷了多次熱點(diǎn)事件和三節(jié)高峰的嚴(yán)峻考驗(yàn),穩(wěn)定性和可靠性都得到了實(shí)際場(chǎng)景的驗(yàn)證。
?
容器化、混合云架構(gòu)
然而好景不長(zhǎng),大量按業(yè)務(wù)拆分的服務(wù)獨(dú)立部署使得服務(wù)的擴(kuò)縮容操作緩慢,直接拉低了峰值流量的應(yīng)對(duì)能力。正好這個(gè)時(shí)候, Docker 提出的一整套圍繞容器部署和管理相關(guān)的生態(tài)系統(tǒng)逐漸完善,于是微博率先在重點(diǎn)業(yè)務(wù)上嘗試了容器化。與此同時(shí),虛擬化、云計(jì)算領(lǐng)域也在飛速發(fā)展。為了低成本高效率地應(yīng)對(duì)各種極端峰值,我們?cè)谌萜骰幕A(chǔ)上探索了公有云和私有云混合部署的模式,研發(fā)了微博 DCP 混合云平臺(tái),實(shí)現(xiàn)了資源的動(dòng)態(tài)擴(kuò)縮容,結(jié)合 Motan RPC 的服務(wù)治理實(shí)現(xiàn)了對(duì)流量的彈性調(diào)度。
至此,微博平臺(tái)在 Java 技術(shù)棧形成了配套完善的一整套服務(wù)體系,有完善的服務(wù)治理相關(guān)組件、明確的 SLA 指標(biāo)、完備的 Trace、監(jiān)控等體系保障微博平臺(tái)的高性能高可用運(yùn)轉(zhuǎn)。
?
跨語言服務(wù)化之路
但微博整體技術(shù)棧比較多樣化,異構(gòu)系統(tǒng)一般通過 RESTful 接口進(jìn)行交互。由于每個(gè)團(tuán)隊(duì)的服務(wù)部署都不盡相同,依賴的服務(wù)訪問往往要經(jīng)過層層轉(zhuǎn)發(fā),此過程中繁重的網(wǎng)絡(luò) I/O 拖長(zhǎng)了請(qǐng)求耗時(shí),影響了系統(tǒng)性能同時(shí)也使得問題排查變得更復(fù)雜。另外,每種語言都有一套自己的系統(tǒng)或者指標(biāo),這也帶來了許多不必要的重復(fù)資源浪費(fèi)。
如何解決跨語言交互,平衡各種語言間服務(wù)治理能力與標(biāo)準(zhǔn)各異的問題?如何對(duì)日常問題快速排查,使上下游業(yè)務(wù)更容易觀測(cè)和聯(lián)動(dòng)?我們認(rèn)為必須要有一套跨語言的服務(wù)治理方案來解決異構(gòu)語言交互以及統(tǒng)一服務(wù)治理標(biāo)準(zhǔn)等問題。所以從 2016 年開始,我們開始探索跨語言服務(wù)化的道路。
Java 和 PHP 是微博內(nèi)部使用最多的兩種語言,所以我們起初的跨語言是立足于微博平臺(tái)的 Java 體系,探索 Java 與 PHP 之間的跨語言調(diào)用。我們最初在 Motan RPC 實(shí)現(xiàn)了 PHP RPC 框架 Yar 的協(xié)議,實(shí)現(xiàn)了服務(wù)調(diào)通,但是這只完成了 Java 和 PHP 之間的跨語言調(diào)用,而其他語言并沒有 Yar 協(xié)議。于是我們又調(diào)研了其他支持跨語言的 RPC 框架,發(fā)現(xiàn) gRPC 可能與我們的需求更接近,于是我們希望通過在 Motan 中添加對(duì) gRPC 協(xié)議的支持來達(dá)到跨語言的目的。
還是以 Java PHP 跨語言為起點(diǎn),除了跨語言服務(wù)調(diào)通外,更為重要的是實(shí)現(xiàn)服務(wù)化的核心——服務(wù)治理功能。這時(shí)我們發(fā)現(xiàn)用 PHP 實(shí)現(xiàn)服務(wù)發(fā)現(xiàn)不太方便,因?yàn)橥ǔ?PHP 是以 PHP-FPM 的形式運(yùn)行在前端服務(wù)器,每個(gè) FPM 進(jìn)程相互獨(dú)立,并沒有一個(gè)統(tǒng)一常駐內(nèi)存的地方來存取服務(wù)發(fā)現(xiàn)回來的結(jié)果以及每次服務(wù)請(qǐng)求的狀態(tài)等基本信息。
我們還嘗試了本地守護(hù)進(jìn)程和 OpenResty 的 Timer 來實(shí)現(xiàn)服務(wù)發(fā)現(xiàn),但也只能實(shí)現(xiàn)最基礎(chǔ)的節(jié)點(diǎn)發(fā)現(xiàn)功能。而對(duì)于復(fù)雜的服務(wù)治理功能,比如需要基于每次請(qǐng)求完成情況而實(shí)現(xiàn)的請(qǐng)求雙發(fā)或者快速失敗等常用服務(wù)治理策略就比較吃力。
另外實(shí)現(xiàn)了基礎(chǔ)服務(wù)發(fā)現(xiàn)功能的 PHP 通過 gRPC 調(diào)用的性能也并沒有 gRPC 宣稱的那么強(qiáng)悍。有時(shí)改造后的效果跟之前 RESTful 接口的訪問性能差不多。因?yàn)樵谖⒉﹫?chǎng)景下,比如取一個(gè) Feed 列表,里面每條微博的 proto 文件就有百十個(gè)字段,每次會(huì)請(qǐng)求回來大量數(shù)據(jù), 而 PHP 在 PB 反序列化方面耗時(shí)非常大,這就直接抵消了 RPC 直連帶來的性能優(yōu)化。
?
從跨語言服務(wù)化到 Service Mesh
拋開大 PB 反序列化帶來的性能損失,類似 PHP 這種原生沒有常駐內(nèi)存控制能力的語言,實(shí)現(xiàn)服務(wù)治理都會(huì)面臨同樣的問題,就算能很自然地實(shí)現(xiàn)服務(wù)治理功能,難道需要每種語言都實(shí)現(xiàn)一套重復(fù)的服務(wù)治理功能嗎?顯然不是這樣的。所以我們就希望引入一個(gè) Agent,來統(tǒng)一解決服務(wù)治理的問題,Client 只需要實(shí)現(xiàn) Motan 協(xié)議解析,直接通過本機(jī) Agent 調(diào)用遠(yuǎn)端服務(wù)即可。這便是 Weibo Mesh 的雛形,也就是目前被大家所熟知的 SideCar 模式代理的 Service Mesh 實(shí)現(xiàn)。
?
那么,我們是如何從跨語言服務(wù)化走到 Service Mesh 這條路的呢?要解答這個(gè)問題,只要弄清楚 Service Mesh 是什么,搞清楚 Service Mesh 解決問題的邊界,答案就一目了然了。
Service Mesh 是什么?這個(gè)詞最早是由開發(fā) Linkerd 的 Buoyant 公司提出,Linkerd 的 CEO William 最早給出定義:服務(wù)網(wǎng)格(Service Mesh)是一個(gè)基礎(chǔ)設(shè)施層,功能在于處理服務(wù)間通信,職責(zé)是負(fù)責(zé)實(shí)現(xiàn)請(qǐng)求的可靠傳遞。在實(shí)踐中,服務(wù)網(wǎng)格通常實(shí)現(xiàn)為輕量級(jí)網(wǎng)絡(luò)代理,與應(yīng)用程序部署在一起,但是對(duì)應(yīng)用程序透明。
我們?cè)诮鉀Q跨語言服務(wù)化中服務(wù)間調(diào)用和統(tǒng)一服務(wù)治理所引入的 Agent 就是這個(gè) Mesh 層。雖然 Service Mesh 是個(gè)新詞,但它描述的問題卻是一個(gè)固有問題,微服務(wù)發(fā)展到一定階段,當(dāng)服務(wù)間的調(diào)用、依賴、服務(wù)治理復(fù)雜到一定程度后,都會(huì)面臨這個(gè)問題。所以 Service Mesh 是服務(wù)化必經(jīng)之路,這就是為什么我們的跨語言服務(wù)化最終會(huì)落腳到 WeiboMesh。
我們基于 Motan-go 實(shí)現(xiàn)了客戶端服務(wù)端的雙向代理,基于微博注冊(cè)中心 Vintage 實(shí)現(xiàn)了對(duì) Agent 的動(dòng)態(tài)指令控制,完成了傳輸與控制的重新定義,并結(jié)合 OpenDCP 平臺(tái)實(shí)現(xiàn)了動(dòng)態(tài)流量調(diào)度和彈性擴(kuò)縮容,保障了服務(wù)的高可用。目前已經(jīng)有很多核心業(yè)務(wù)完成了基于 WeiboMesh 的升級(jí)改造,比如大家經(jīng)常使用的微博熱搜、熱門微博等。我們從 2016 年開始起步,一路摸索,走到現(xiàn)在與 Service Mesh 理念完美契合,完成了 WeiboMesh 的主體建設(shè)。
接下來的幾篇文章我會(huì)就 WeiboMesh 的具體實(shí)現(xiàn)過程與探索中的經(jīng)驗(yàn)做一些總結(jié)和探討。
進(jìn)一步學(xué)習(xí) Service Mesh
針對(duì) Service Mesh 的特點(diǎn),落地過程中如何根據(jù)現(xiàn)有架構(gòu)做出合理的取舍?
這個(gè)過程中有哪些容易掉入的陷阱?如何避免?
經(jīng)過最近一年的發(fā)展,Service Mesh 形成了哪些事實(shí)規(guī)范?
經(jīng)歷過整個(gè)過程之后,對(duì)于架構(gòu)我有了哪些更深入的思考?
總結(jié)
以上是生活随笔為你收集整理的Service Mesh 实践指南:从单体应用到 Service Mesh 的曲折历程的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Web架构的演化
- 下一篇: 【看图识算法】这是你见过最简单的 “算法