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