貨拉拉服務化實踐-為啥都愛“造輪子”?

陶然陶然發表於2022-12-16

   一、背景

  貨拉拉於2013年創立,成長於粵港澳大灣區,是一家從事同城/跨城貨運、企業版物流服務、搬家、零擔、汽車租售及車後市場服務的網際網路物流商城;公司技術經過近十年的發展,內部微服務的數量達到 1000+

  貨拉拉最早期的服務化技術架構是基於 PHP (少量 Java )經過域名走 http 協議,進行內部服務之間的相互訪問,這種簡單的技術方式支撐著貨拉拉早期業務的快速迭代開發  

  但這種“快”也帶來一些隱患,當我們的業務規模、資料規模、服務規模都發生了很大的變化,“快”引發的一些問題變得越來越凸顯;具體到服務化架構而言,主要問題體現在:內部服務之間的互動關係越來越複雜,鏈路的穩定性面臨挑戰,同時服務之間缺乏基本的治理能力(路由、熔斷、降級、限流等等),無法從容的應對多變的業務形態和突發的流量高峰帶來的問題

  在這種早期的背景下,貨拉拉引入服務化架構刻不容緩,但同時我們無法做到零歷史負擔和一步改造到位,因此我們把服務化架構建設的核心思路主要聚焦在如下兩個方面:

  首先要考慮如何相容生產環境大量現存的老服務(PHP/Java),同時可以逐步進行改造遷移,不阻塞業務迭代

  其次是要結合貨拉拉的自身情況,在相對可控、有保障的前提下去做服務化相關的治理,包括業務情況以及研發人員的特點

   二、為啥選擇“造輪子”

  貨拉拉服務化建設初期,團隊嘗試考慮過多種現有的開源方案,但都或多或少的遇到了無法解決的問題或者無法接受的維護改造成本,最終我們選擇了自研的方案,也就是大家熟知的“造輪子”

  下面將說明我們為啥沒有直接使用 dubbo 或 istio 以及背後的考慮因素

  2.1. 為啥不直接使用 Dubbo

  Dubbo 作為國內最成熟、最廣為人知的微服務框架,首先進入我們考慮的範圍,但在結合貨拉拉的現狀評估以後,遇到了如下侷限性:

  沒有直接提供對 PHP 的支援,即使不考慮對 PHP 新服務端的支援,也缺乏在統一的服務發現和服務治理機制下進行 PHP 服務的客戶端呼叫

  擴充套件性太靈活,擴充套件點太多(100+),作為開源產品是一種優勢,但是對於公司內部來說,很難統一和管理使用姿勢,對基礎設施的適配要求也變的更高

  要相容貨拉拉的基礎設施現狀(可觀測性、註冊中心選型、釋出機制等等),Dubbo 無法做到開箱即用,需要進行工作量不小的定製工作

  沒有提供直接的服務治理能力(需要結合其他產品或自己擴充套件)、控制檯能力弱、程式碼中大量處理歷史相容問題等等

  以上侷限性有些無法直接解決,有些需要透過二次開發進行定製,但是成本也不低,因此我們最終沒有直接採用 Dubbo,但自研方案參考了大量 Dubbo 實現上的優秀設計

  2.2. 為啥不考慮 Istio

  Istio 作為當下最流行的 service mesh 解決方案,也進入了我們的調研範圍,他提供的多語言和透明升級的能力對我們非常有吸引力,同時服務治理能力下沉的理念也是我們非常認同的未來趨勢;但是與此同時,Istio 方案對我們來說面臨的侷限性也十分明顯:

  內建提供的服務治理能力有限,且 envoy filter 擴充套件難度成本較大(無論 CPP/Lua/Proxy-Wasm)

  預設採用的透明流量劫持,且不說 iptables 帶來的複雜度,還有很多非服務化流量可能帶來相容性問題(遇到過 http1.0、JDK 低版本客戶端等等問題)

  K8S 環境是一等公民,貨拉拉還存在很多 VM 的環境

  在服務數量較多的情況下,叢集服務配置過大、MCP 擴充套件問題等等

  同時 Istio 架構複雜,呼叫鏈路變長,貨拉拉技術團隊當前也缺乏 Istio 的運維經驗 ,加上國內也缺少真正大規模 Istio 落地的大廠經驗與案例,所以我們也沒有使用 Istio 方案

  2.3. 其他考慮因素

  除了上面兩個章節中提到的因素外,還有兩個主要因素的共同作用,使得我們最終選擇了自研的方案

  公司業務場景的多樣性和特殊性,需要對架構和程式碼都要有決定的掌控能力

  開源的控制面大多比較簡潔,無法滿足我們的訴求,且我們需要上報更多的資訊方便我們進行服務管理和框架運營

   三、核心設計

  3.1. 架構設計

  如下圖所示,貨拉拉服務化整體架構設計借鑑了 service mesh 的一些理念,主要區分控制面和資料面,並使用開源專案的相關元件進行支撐  

  資料面:現階段主要指的 Java SDK 和 後面提到的 PHP Proxy,提供服務化所需的接入 API,RPC 協議、服務治理等等能力,通常執行在業務程式或者作為業務程式的 sidecar

  控制面:除了作為傳統服務化控制面提供服務治理和服務生命週期管理能力外,也充當服務化的工具中心和資料運營中心

  主要支撐元件

  使用 Apollo 作為配置中心,並區別於傳統 service mesh 資料面依賴於 Pilot 等元件,我們透過 apollo 解耦資料面與控制面,不額外增加執行時依賴

  使用 Consul 叢集作為註冊中心元件

  3.2. PHP 與“泛化呼叫”

  前面提到我們需要考慮如何相容生產環境大量現存的 PHP 老服務,好在我們內部達成共識,不需要考慮對 PHP 新服務端的支援,因此問題就可以簡化為兩個主要問題:

  老的 PHP 服務如何被服務發現?

  Java 服務怎麼透過類似標準 RPC 的方式呼叫老的 PHP 服務?

  首先針對老的 PHP 服務如何被服務發現,我們設計瞭如下圖所示的解決方案:透過與一個 sidecar(命名 GoProxy,非 golang 的 GOPROXY) 程式協同,來解決服務註冊、動態配置獲取等等問題  

  其次對於 Java 服務怎麼透過類似標準 RPC 的方式呼叫老的 PHP 服務的問題,我們設計了內部稱為“泛化呼叫”(非傳統 RPC 泛化呼叫)的 RPC 客戶端,可以使用和標準 RPC 一致的接入和配置方式進行呼叫,並且獲取統一的服務發現、服務路由和服務治理(僅客戶端)能力  

  3.3. RPC 協議

  協議是 RPC 的核心,它規範了資料在網路中的傳輸內容和格式,框架的通用性、效能、穿透性、擴充套件性等都與 RPC 協議的選擇息息相關

  貨拉拉結合內部情況同時提供基於 HTTP1.1 的 JSON-RPC 協議和基於 HTTP2.0 的 gRPC 協議,兩種協議除了定義和呼叫方式外,其他框架能力和服務治理能力都是統一的、通用的

  預設使用 JSON-RPC 協議,簡單易用,並且能一定程度相容老服務使用的 HTTP 協議

  有強契約、高效能、流式呼叫或跨語言需求的選擇 gRPC 協議  

  3.4. SDK 整體設計

  正如前面所提,SDK(Java) 的整體設計參考了 Dubbo 實現上的優秀設計,這裡主要介紹一下 SPI 機制、服務自省和服務呼叫鏈

  首先 SPI 機制在 Dubbo 的基礎上我們做了一些最佳化:

  新增 Internal SPI,標記僅僅支援框架本身進行擴充套件的 SPI,平衡擴充套件性與使用方法上的收斂

  最佳化自動包裝顯示使用 @Wrapper 註解,並提供 Ignore 能力

  最佳化自動裝配顯示使用 @Inject 註解  

  其次是服務自省機制,解耦了傳統臃腫的服務註冊中心:透過 Consul 進行應用級服務發現,使用 Apollo 作為動態配置中心,控制面 Admin 接受服務後設資料和各種事件上報充當後設資料中心;同時服務自省涉及到的核心物件如下所示  

  

  最後對於 SDK 的服務核心呼叫鏈設計,如下圖所示,每個核心物件都是框架擴充套件點,可以實現各種服務治理相關的述求,並提供給業務一定的擴充套件和自定義能力

  Cluster 叢集,用於叢集容錯

  Directory 服務目錄,用於服務發現

  Router 服務路由

  LoadBalance 負載均衡

  Filter 呼叫攔截器,可以同時作用於服務端和客戶端

  ClusterFilter 客戶端服務目錄之前的呼叫攔截器  

  3.5. 服務治理與CommandKey

  在解決了服務化的基本 RPC 能力之後,服務治理能力建設就是重中之重,貨拉拉目前建設的治理能力有如下幾類:

  服務容錯:客戶端 Fallback 機制、服務預熱、無損上下線、異常處理機制等等

  服務路由:版本路由、灰度路由、多 AZ 路由等等

  服務流量治理:限流、熔斷、降級、動態超時、動態日誌、服務鑑權、服務驗證等等

  另外對於服務流量治理的設計,我們在借鑑了 Sentinel “資源”的思路,設計了 CommandKey 機制,每一次流量都能轉換為對應的 CommandKey,然後整個治理規則的配置和執行都可以與之進行關聯和設計

  而且 CommandKey 的設計是結構化,與服務的實際結構相似,可以很自然的實現與服務結構一一對應、規則的層級覆蓋等等功能,極大的簡化了服務治理的管理和理解成本  

   四、建設成果

  經過團隊近兩年的努力,截止目前(2022年中),貨拉拉服務化建設的主要成果如下:  

  接入服務數: 700+

  服務例項數: 5000+

  每日呼叫量: 百億級

   五、後續演進

  目前貨拉拉服務化框架建設初步滿足了公司的業務發展和研發訴求,但仍然面臨著眾多挑戰,後續我們將從多個方面持續完善服務化架構的建設與演進  

  持續提升接入效率和使用體驗:使用 API 調優, 控制面建設等等

  不斷完善服務治理能力,覆蓋服務從開發、測試一直到線上執行的各階段對服務治理能力的需求

  Java SDK Proxyless 建設:結合 JavaAgent 技術和版本管理方案,一定程度解決 Java SDK 升級難以及版本碎片化的問題

  多語言(Golang)與 Runtime 建設:在滿足公司部分團隊逐漸增長的 Golang RPC 需求(多語言)的同時進行 Runtime 建設,下沉並逐步統一服務治理能力,也進一步解決多語言與版本升級難等問題

來自 “ 貨拉拉技術 ”, 原文作者:謝剛;原文連結:http://server.it168.com/a2022/1216/6780/000006780953.shtml,如有侵權,請聯絡管理員刪除。

相關文章