Dubbo Mesh 在閒魚生產環境中的落地實踐

本文做者至簡曾在 2018 QCon 上海站以《Service Mesh 的本質、價值和應用探索》爲題作了一次分享,其中談到了 Dubbo Mesh 的總體發展思路是「借力開源、反哺開源」,也講到了 Service Mesh 在阿里巴巴的發路徑將經歷如下三大階段:算法

  • 撬動
  • 作透價值滲透
  • 實現技術換代

Dubbo Mesh 在閒魚生產環境的落地,分享的是以多語言爲撬動點的階段性總結。編程

文章首發於「QCon」,阿里巴巴中間件受權轉載。緩存

閒魚場景的特色

閒魚採用的編程語言是 Dart,思路是經過 Flutter 和 Dart 實現 iOS、Android 兩個客戶端以及 Dart 服務端,以「三端一體」的思路去探索多端融合的高效軟件開發模式。更多細節請參考做者同事陳新新在 2018 QCon 上海站的主題分享《Flutter & Dart 三端一體化開發》。本文將關注三端中的 Dart 服務端上運用 Dubbo Mesh 去解耦 Dubbo RPC 框架的初步實踐成果。微信

Dart 服務端是一個服務調用膠水層,收到來自接入網關發來的 HTTP 請求後,經過 C++ SDK 調用集團普遍提供的 Dubbo 服務完成業務邏輯處理後返回結果。然而,C++ SDK 的功能與 Java 的存在必定的差距,好比缺失限流降級等對於保障大促穩定性很重要的功能。從長遠發展的角度,閒魚團隊但願經過 Dubbo Mesh 能屏蔽或簡化不一樣技術棧使用中間件(好比,RPC、限流降級、監控、配置管理等)的複雜性。這一訴求的由來,是閒魚團隊經過幾個月的實踐,發如今 Dart 語言中經過 C++ SDK 逐個接入不一樣中間件存在定製和維護成本高的問題。值得說明,所謂的「定製」是由於 C++ SDK 的能力弱於 Java SDK 而要作補齊所致。架構

Dart 服務端自身的業務邏輯很輕且在一些場景下須要調用 20 屢次 Dubbo 服務,這對於 Dubbo Mesh 的技術挑戰會顯得更大。在 Dubbo Mesh 還沒在生產環境落地過而缺少第一手數據的情形下,其性能是否徹底知足業務的要求是你們廣泛關心的。併發

架構與實現

Dubbo Mesh 架構圖(監控部分未表達)

Dubbo Mesh 架構圖(監控部分未表達)框架

圖中的虛框表明了一個Pouch容器(也能夠是一臺物理機或虛擬機)。左邊兩個容器部署了 Dubbo Mesh,剩下最右邊的則沒有。目前 Dubbo Mesh 主要包含 Bonder、Pilot、Envoy 三個進程,以及被輕量化的 Thin SDK。其中:less

  • Envoy 承擔了數據平面的角色,全部 mesh 流量將由它完成服務發現與路由而中轉。Envoy 由 Lyft 初創且目前成爲了 CNCF 的畢業項目,咱們在之上增長了對 Dubbo 協議的支持,並將之反哺到了開源社區(還有很多代碼在等待社區 review 經過後才能進到 GitHub 的代碼倉庫)。
  • Pilot 和 Bonder 共同承擔控制平面的角色,實現服務註冊、進程拉起與保活、集羣信息和配置推送等功能。Pilot 進程的代碼源於開源 Istio 的 pilot-discovery 組件,咱們針對阿里巴巴集團環境作了必定的改造(好比,與Nacos進行適配去訪問服務註冊中心),且採用下沉到應用機器的方式進行部署,這一點與開源的集羣化部署很不同。背後的思考是,Pilot 的集羣化部署對於大規模集羣信息的同步是很是大的一個挑戰,今天開源的 Istio 並不具有這一能力,將來須要 Nacos 團隊對之進行加強,在沒有徹底準備好前經過下沉部署的方式能加速 Service Mesh 的探索歷程。
  • Thin SDK 是 Fat SDK 通過裁剪後只保留了對 Dubbo 協議進行編解碼的能力。爲了容災,當 Thin SDK 位於 Consumer 側時增長了一條容災通道,細節將在文後作進一步展開。

數據鏈路所有采用單條 TCP 長鏈接,這一點與非 mesh 場景是一致的。Pilot 與 Envoy 兩進程間採用的是 gRPC/xDS 協議進行通信。編程語言

圖中同時示例了 mesh 下的 Consumer 能同時調用 mesh 下的服務(圖中以www.mesh.com 域名作示例)和非 mesh 下的服務(圖中以 www.non-mesh.com 域名作示例)。閒魚落地的場景爲了不對 20 多個依賴服務進行改造,流量走的是 mesh 下的 Consumer 調用非 mesh 下的 Provider 這一形式,讀者能夠理解爲圖中最左邊的容器部署的是 Dart 服務端,它將調用圖中最右邊容器所提供的服務去實現業務邏輯。分佈式

容災

從 Dubbo Mesh 下的 Provider 角度,因爲一般是集羣化部署的,當一個 Provider 出現問題(不管是 mesh 組件引發的,仍是 Provider 自身致使的)而使服務沒法調通時,Consumer 側的 Envoy 所實現的重試機制會將服務請求轉發到其餘 Provider。換句話說,集羣化部署的 Provider 自然具有必定的容災能力,在 mesh 場景下無需特別處理。

站在 Dubbo Mesh 的 Consumer 立場,若是徹底依賴 mesh 鏈路去調用 Provider,當 mesh 鏈路出現問題時則會致使全部服務都調不通,這每每會引起業務可用性問題。爲此,Thin SDK 中提供了一個直連 Provider 的機制,只不過實現方式比 Fat SDK 輕量了許多。Thin SDK 會按期從 Envoy 的 Admin 接口獲取所依賴服務的 Provider 的 IP 列表,以備檢測到 mesh 鏈路存在問題時用於直連。好比,針對每個依賴的服務獲取最多 10 個 Provider 的 IP 地址,當 mesh 鏈路不通時以 round robin 算法向這些 Provider 直接發起調用。因爲容災是針對 mesh 鏈路的短暫失敗而準備的,因此 IP 地址的多少並非一個很是關鍵的點。Thin SDK 檢測 mesh 鏈路的異常大體有以下場景:

  • 與 Envoy 的長鏈接出現中斷,這是 Envoy 發生 crash 所致。
  • 所發起的服務調用收到 No Route Found、No Healthy Upstream 等錯誤響應。

優化

在閒魚落地 Dubbo Mesh 的初期咱們走了一個「彎路」。

具體說來,最開始爲了快速落地而採用了 Dubbo over HTTP 1.1/2 的模式,也即,將 Dubbo 協議封裝在 HTTP 1.1/2 的消息體中完成服務調用。這一方案雖然能很好地享受 Envoy 已完整支持 HTTP 1.1/2 協議而帶來的開發工做量少的好處,但性能測試代表其資源開銷並不符合你們的預期。體現於,不只 Consumer 側使用 mesh 後帶來更高的 CPU 開銷,Provider 側也由於要提供經過 HTTP 1.1/2 進行調用的能力而致使多出 20% 的 CPU 開銷且存在改造工做。最終,咱們回到讓 Envoy 原生支持 Dubbo 協議的道路上來。

Envoy 支持 Dubbo 協議經歷了兩大階段。第一個階段 Envoy 與上游的通信並無採用單條長鏈接,使得 Provider 的 CPU 開銷由於多鏈接而存在不可忽視的遞增。第二個階段則徹底採用單條長鏈接,經過多路複用的模式去除了前一階段給 Provider 所帶去的額外 CPU 開銷。

Dubbo Mesh 在閒魚預發環境上線進行性能與功能驗證時,咱們意外地發現,Istio 原生 Pilot 的實現會將全量集羣信息都推送給處於 Consumer 側的 Envoy(Provider 側沒有這一問題),致使 Pilot 自身的 CPU 開銷過大,而頻繁的全量集羣信息推送也使得 Envoy 不時會出現 CPU 負荷毛刺並遭受沒有必要的內存開銷。爲此,咱們針對這一問題作了集羣信息按需加載的重大改造,這一優化對於更大規模與範圍下運用 Dubbo Mesh 具備很是重要的意義。優化的大體思路是:

  • Thin SDK 提供一個 API 供 Consumer 的應用在初始化時調用,周知其所需調用的服務列表。
  • Thin SDK 經過 HTTP API 將所依賴的服務列表告訴 Bonder,Bonder 將之保存到本地文件。
  • Envoy 啓動時讀取 Bonder 所保存的服務列表文件,將之看成元信息轉給 Pilot。
  • Pilot 向 Nacos 只訂閱服務列表中的集羣信息更新消息且只將這些消息推送給 Envoy。

監控

可觀測性(observability)是 Service Mesh 很是重要的內容,在服務調用鏈路上插入了 Envoy 的情形下,越發須要經過更強的監控措施去治理其上的全部微服務。Dubbo Mesh 的監控方案並無使用 Istio/Mixer 這樣的設計,而是沿用了阿里巴巴集團內部的方式,即信息由各進程以日誌的形式輸出,而後經過日誌採集程序將之送到指定的服務端進行後期加工並最終展現於控制檯。目前 Dubbo Mesh 經過 EagleEye 去跟蹤調用鏈,經過ARMS去展現其餘的監控信息。

性能評估

爲了評估 Dubbo Mesh 的性能可否知足閒魚業務的須要,咱們設計了以下圖所示的性能比對測試方案。

其中:

  • 測試機器是阿里巴巴集團生產環境中的 3 臺 4 核 8G 內存的 Pouch 容器。
  • 藍色方框表明的是進程。測試數據所有從部署了 DartServer 和 Envoy 兩進程的測試機 2 上得到。
  • 性能數據分別在非 mesh(圖中紅色數據流)和 mesh(圖中藍色數據流)兩個場景下得到。顯然,Mesh 場景下的服務流量多了 Envoy 進程所帶來的一跳。
  • DartServer 收到來自施壓的 Loader 進程所發來的一個請求後,將發出 21 次到 Provider 進程的 RPC 調用。在評估 Dubbo Mesh 的性能時,這 21 次是串行發出的(下文列出的測試數據是在這一情形下收集的),實際閒魚生產環境上線時考慮了進行並行發送去進一步下降總體調用時延(即使沒有 mesh 時,閒魚的業務也是這樣實現的)。
  • Provider 進程端並無部署 Envoy 進程。這省去了初期引入 Dubbo Mesh 對 Provider 端的改形成本,下降了落地的工做量和難度。

設計測試方案時,咱們與閒魚的同窗共創瞭如何回答打算運用 Dubbo Mesh 的業務方必定會問的問題,即「使用 Dubbo Mesh 後對 RT(Response Time)和 CPU 負荷的影響有多大」。背後的動機是,業務方但願經過 RT 這一指標去了解 Dubbo Mesh 對用戶體驗的影響,基於 CPU 負荷的增加去掌握運用新技術所引起的成本。

面對這一問題一般的回答是「在某某 QPS 下,RT 增長了 x%,CPU 負荷增長了 y%」,但這樣的回答若是不進行具體測試是沒法給出的(會出現「雞和蛋的問題」)。由於每一個業務的自然不一樣使得一個完整請求的 RT 會存在很大的差異(從幾毫秒到幾百毫秒),而實現業務邏輯所需的計算量又最終決定了機器的 CPU 負荷水平。基於此,咱們設計的測試方案在於評估引入 Dubbo Mesh 後,每通過一跳 Envoy 所引入的 RT 和 CPU 增量。當這一數據出來後,業務方徹底能夠基於本身業務的現有數據去計算出引入 Dubbo Mesh 後的而掌握大體的影響狀況。

顯然,背後的邏輯假設是「Envoy 對於每一個 Dubbo 服務調用的計算量是同樣的」,事實也確實如此。

測試數據

如下是 Loader 發出的請求在併發度爲 100 的情形下所採集的數據。

表中:

  • Envoy 的 QPS 是 Loader 的 21 倍,緣由在上面測試方案部分有交代。
  • 「單跳」的數據是從「21 跳合計」直接除以 21 所得,其嚴謹性值得商榷,但用於初步評估仍具參考價值(有數據比沒有數據強)。
  • 「整機負荷」表明了在 mesh 場景下測試機器 2 上 DartServer 和 Envoy 兩進程的 CPU 開銷總和。測試代表,CPU 負荷高時 Envoy 帶來的單跳 RT 增幅更大(好比表中 Loader 的 QPS 是 480 時)。給出整機負荷是爲了提醒讀者關注引入 mesh 前業務的正常單機水位,以便更爲客觀地評估運用 Dubbo Mesh 將帶來的潛在影響。
  • 「CPU 負荷增幅」是指 CPU 增長的幅度。因爲測試機是 4 核的,因此整機的 CPU 負荷是 400。

從表中數據來看,隨着機器總體負荷的增長「CPU 負荷增幅」在高段存在波動,這與 RT 在高段的持續增大存在相關,從 RT 在總體測試中徹底符合線性增加來看總體數據合理。固然, 後面值得深刻研究數據背後的隱藏技術細節以便深刻優化。

線上數據

Dubbo Mesh 正式生產環境上線後,咱們經過對上線先後的某接口的 RT 數據進行了全天的比對,以便大體掌握 mesh 化後的影響。2019-01-14 該接口全面切成了走 Dubbo Mesh,咱們取的是 2019-01-20 日的數據。

圖中藍色是 mesh 化後的 RT 表現(RT 均值 3.3),而橙色是 mesh 化前的 RT 表現(RT 均值 3.27,取的是 2019-01-13 的數據)。因爲線上天天的環境都有所不一樣,要作絕對的比較並不可能。但經過上面的比較不難看出,mesh 化先後對於總體 RT 的影響至關的小。當總體 RT 小於 5 毫秒是如此,若是總體 RT 是幾10、幾百毫秒則影響就更小。

爲了幫助更全面地看待業務流量的波動特色,下面分別列出了兩天非 mesh(2019-01-06 和 2019-01-13)和兩天 mesh(2019-01-20 和 2019-01-23)的比對數據。

總之,生產環境上的數據表現與前面性能評估方案下所得到的測試數據能很好地吻合。

洞見

Dubbo Mesh 在閒魚生產環境的落地實踐讓咱們收穫了以下的洞見:

  • 服務發現的時效性是 Service Mesh 技術的首要關鍵。 以集羣方式提供服務的情形下(這是分佈式應用的常態),由於應用發佈而致使集羣中機器狀態的變動如何及時準確地推送到數據平面是極具挑戰的問題。對於阿里巴巴集團來講,這是 Nacos 團隊致力於解決的問題。開源版本的 Istio 可否在生產環境中運用於大規模分佈式應用也首先取決於這一能力。頻繁的集羣信息推送,將給控制平面和數據平面都帶去負荷擾動,如何經過技術手段控制好擾動是須要特別關注的,對於數據平面來講編程語言的「肯定性」(好比,沒有 VM、沒有 GC)在其中將起到不可忽視的做用。
  • 數據平面的軟件實現最大程度地減小內存分配與釋放將顯著地改善性能。有兩大舉措能夠考慮:
  1. 邏輯與數據相分離。 以在 Envoy 中實現 Dubbo 協議爲例,Envoy 每收到一個 RPC 請求都會動態地建立 fitler 去處理,一旦實現邏輯與數據相分離,filter 的建立對於每個 worker 線程有且只有一次,經過這一個 filter 去處理全部的 RPC 請求。
  2. 使用內存池。 Envoy 的實現中基本沒有用到內存池,若是採用內存池對分配出來的各類 bufffer 經過鏈表進行緩存,這將省去大量的內存分配與釋放而改善性能。再則,對於處理一個 RPC 請求而屢次分散分配的動做整合成集中一次性分配也是值得運用的優化技巧。
  • 數據平面的 runtime profiling 是關鍵技術。 Service Mesh 雖然對業務代碼沒有侵入性,但對服務流量具備侵入性,如何在出現業務毛刺的情形下,快速地經過 runtime profiling 去發現問題或自證清白是很是值得關注的點。

心得

一年不到的探索旅程,讓團隊更加篤定「借力開源,反哺開源」的發展思路。隨着對 Istio 和 Envoy 實現細節的更多掌握,團隊很強列地感覺到了走「站在巨人的肩膀上」發展的道路少走了不少彎路,除了快速跟進業界的發展步伐與思路,還將省下精力去作更有價值的事和創新。

此外,Istio 和 Envoy 兩個開源項目的工程質量都很高,單元測試等質量保證手段是平常開發工做中的基礎環節,而咱們也徹底採納了這些實踐。好比,內部搭建了 CI 環境、每次代碼提交將自動觸發單元測試、代碼通過 code review 並完成單元測試才能入庫、自動化性能測試等。

展望

在 2019 年接下來的日子,咱們將着手:

  • 與 Sentinel 團隊造成協力,將 Sentinel 的能力歸入到 Dubbo Mesh 中補全對 HTTP 和 Dubbo 協議的限流、降級和熔斷能力。
  • 在阿里巴巴集團大範圍 Kubernetes(Sigma 3.1)落地的背景下,與兄弟團隊探索更加優雅的服務流量透明攔截技術方案。
  • 迎合 Serverless 的技術發展趨勢,深化經過 Dubbo Mesh 更好地輕量化應用,以及基於 Dubbo Mesh 對服務流量的自然敏感性去更好地實現 auto-scaling。
  • 在產品的易用性和工程效率方面踏實進取。

將來,咱們將及時與讀者分享阿里巴巴集團在 Service Mesh 這一新技術領域的探索成果,也期待與你們有更多的互動交流。

本文做者:至簡,阿里巴巴中間件高級技術專家,是阿里巴巴集團 Service Mesh 方向的重要參與者和推進者。

關於 Dubbo Mesh 的首次公開分享

 

原文連接 更多技術乾貨 請關注阿里云云棲社區微信號 :yunqiinsight

相關文章
相關標籤/搜索