歡迎光臨
每天分享高質量文章

服務框架的技術棧(作者:弔打我 96 年的表弟)

點擊上方“芋道原始碼”,選擇“置頂公眾號”

技術文章第一時間送達!

原始碼精品專欄

 

1. 概述

架構的改變,往往是因為業務規模的擴張。

隨著業務規模的擴張,為了滿足業務對技術的要求,技術架構需要從單體應用架構升級到分佈式服務架構,來降低公司的技術成本,更好的適應業務的發展。分佈式服務架構的諸多優勢,這裡就不一一列舉了,今天圍繞的話題是服務框架,為了推行服務化,必然需要一套易用的服務框架,來支撐業務技術架構升級。

2. 服務框架

服務框架的核心是服務呼叫,分佈式服務架構中的服務分佈在不同主機的不同行程上,服務的呼叫跟單體應用行程內方法呼叫的本質區別就是需要借助網絡來進行通信。

下圖是服務框架的架構圖,主流的服務框架的實現都是這套架構,如 Dubbo、SpringCloud 等。

img
  • Invoker 是服務的呼叫方

  • Provider 是服務的提供方

  • Registry 是服務的註冊中心

  • Monitor 是服務的監控模塊

Invoker 和 Provider 分別作為服務的呼叫和被呼叫方,這點很明確。但是僅有這兩者還是不夠的,因為作為呼叫方需要知道服務部署在哪,去哪呼叫服務,所以有了 Registry 模塊,它的功能是給服務提供方註冊服務,給服務呼叫方發現服務。Monitor 作為服務的監控模塊,負責服務的呼叫統計以及鏈路分析功能,也是服務治理重要的一環。

3. 核心模塊

下圖是服務框架的流程圖,我們分服務註冊、發現、呼叫三個方面來進行流程分解。

img

服務註冊是服務提供方向註冊中心註冊服務信息;當提供服務應用下線時,負責將服務註冊信息從註冊中心刪去。

服務發現是服務呼叫方從註冊中心訂閱服務,獲取服務提供方的相關信息;當服務註冊信息有變更時,註冊中心負責通知到服務呼叫方。

服務呼叫是服務呼叫方通過從註冊中心拿到服務提供方的信息,向服務提供方發起服務呼叫,獲取呼叫結果。

對照上述流程圖,我們按照請求的具體過程進行分析。

作為服務呼叫方 Invoker 的具體流程是: a. Request 從下往上,由於服務呼叫方只能拿到服務提供方提供的 API 接口或者 API 接口的 JAR 包,所以服務呼叫方需要經過一層代理 Proxy 來偽裝服務的實現; b. 經過代理 Proxy 之後,會經過路由 Router、負載均衡 LoadBalance 模塊,目的是從一堆從註冊中心拿到的服務提供方信息中選出最合適的服務提供方機器進行呼叫。另外,還會經過 Monitor 監控等模塊; c. 接著會經過服務編碼 Codec 模塊,這個模塊的目的是因為請求在網絡傳輸前需要按照通信協議以及物件的序列化方式,對傳輸的請求進行編解碼; d. 最終會經過網絡通信 Transporter 模塊,這個模塊將 Codec 編碼好的請求進行傳輸。

作為服務提供方 Provider 的具體流程是: a. Request 從上往下,經過網絡通信 Transporter 模塊,獲取到的是由呼叫方發送的Request位元組陣列。 b. 接著經過服務編碼 Codec 模塊,根據通信協議解出一個完整的請求包,然後使用具體的序列化方式反序列化成請求物件。 c. 緊接著會經過監控、限流、鑒權等模塊。 d. 最終會執行服務的真正業務實現 ServiceImpl,執行完後,結果按原路傳回。

按照上述流程分解一個服務框架的相關工作,再去看一些開源的服務框架也就不難理解了。一般服務框架的核心模塊應該有註冊中心、網絡通信、服務編碼(通信協議、序列化)、服務路由、負載均衡,服務鑒權,可用性保障(服務降級、服務限流、服務隔離)、服務監控(Metrics、Trace)、配置中心、服務治理平臺等。

3.1 註冊中心

註冊中心是用來註冊和發現服務的,需要具備的基本功能有註冊服務、下線服務、發現服務、通知服務變更等。 當前使用比較多的開源註冊中心有 Zookeeper、ETCD、Eureka 等。 Zookeeper 與 ETCD 在整體架構上都比較類似,使用方式非常便捷,應用比較廣泛。這兩套系統按照 CAP 理論,屬於 CP 系統,可用性會差一點,但是作為中小規模服務註冊中心,還是游刃有餘,並沒有某些人說的那麼差勁。 Eureka 是 Spring Cloud Netflix 微服務套件中的一部分,很不幸的是 Eureka 2.0 開源工作宣告停止。

3.2 網絡通信

服務的呼叫方和提供方都來自不同的主機的不同的行程,所以要進行呼叫,必然少不了網絡通信。可以說網絡通信是分佈式系統的重中之重,網絡通信框架的好壞直接影響服務框架的性能。從零實現一套性能高,穩定性強的通信框架還是非常難的,好在目前已經有很多開源的高性能的網絡通信框架。 針對 Java 生態有 Mina、Netty 等,目前使用最廣泛的也當屬 Netty。Netty 使用的是 per thread one eventloop 執行緒模型,這點與 Nginx 等其他高性能網絡框架類似。另外,Netty 非常易用,所以網絡通信選擇 Netty 框架自然是毫無疑問的。

3.3 服務編碼

記憶體物件要經過網絡傳輸前需要做兩件事:第一是確定好通信協議,第二序列化。

3.3.1 通信協議

通信協議說白了在發送資料前按照一定的格式來處理資料,然後進行發送,保證接收方拿到資料知道按照什麼樣的格式進行處理。 有些同學可能不理解,為什麼需要通信協議,不是有 TCP、UDP 協議了嗎?這裡說的不是傳輸層的通信協議,應該是應用層的協議類似 HTTP。因為的 TCP 協議雖然已經保證了可靠有序的傳輸,但是如果沒有一套應用層的協議,就不知道發過來的位元組資料是不是一個完整的資料請求,或者說是多個請求的位元組資料都在一起,無法拆分,這就是是所謂的粘包,需要按照協議進行拆包,拆成一個個完整的請求包進行處理。 協議的實現上一般大廠或者開源的服務框架選擇自建協議,更偏向服務領域。如 Dubbo,當然也有些框架直接使用 HTTP,HTTP/2,比如 GRPC 使用的就是 HTTP/2。

3.3.1 序列化

由於向網絡層發送的資料必須是位元組資料,不可能直接將一個物件發送到網絡,所以在發送物件資料前,一般需要將物件序列化成位元組資料,然後進行傳輸。 在服務方收到網絡的位元組資料時,需要經過反序列化拿到相關的物件。 序列化的實現目前現成比較多,如 Hessian、JSON、Thrift、ProtoBuf 等。Thrift 和 ProtoBuf 能支持跨語言,性能比較好,不過使用時需要編寫 IDL 檔案,有點麻煩。Hessian、JSON 使用起來比較友好,但是性能會差一點。

3.4 服務路由

服務路由指的是向服務提供方發起呼叫時,需要根據一定的演算法從註冊中心拿到的服務方地址信息中選擇其中的一批機器進行呼叫。 路由的演算法一般是根據場景來進行選擇的,比如有些公司實施兩地三中心這種高可用部署,但是由於兩地的網絡延時比較大,那這時就可以實施同地區路由策略,比如上海的呼叫方請求會優先選擇上海的服務進行呼叫,來降低網絡延時導致的服務端到端的呼叫耗時。 還有些框架支持腳本配置來進行定向路由策略。

3.5 負載均衡

負載均衡是緊接著服務路由的模塊,負載均衡負責將發送請求均勻合理的發送到服務提供方的節點上,而備選機器,一般就是經過路由模塊選擇出來的。 負載均衡的演算法有很多,如 RoundRobin、Random、LeastActive、ConsistentHash 等。而且這些演算法一般都是基於權重的增強版本,因為需要根據權重來調節每台服務節點的流量。

3.6 服務鑒權

服務鑒權是服務安全呼叫的基礎,雖然絕大部分服務都是公司內部服務,但是對於敏感度較高的資料還是需要進行鑒權的。鑒權的服務需要對服務的呼叫方進行授權,未經授權的呼叫方是不能夠呼叫該服務的。 關於服務鑒權的實現大都是基於 token 的認證方案,如 JWT(JSON Web Token) 認證。

3.7 可用性保障

可用性保障模塊是服務高可用的一個重要保證。服務在交互中主要分成呼叫方和提供方兩種角色,作為服務呼叫方,可以通過服務降級提升可用性。作為服務提供方,可以通過服務限流、服務隔離來保證可用性。

3.7.1 服務降級

服務降級指的是當依賴的服務不可用時,使用預設的值來替代服務呼叫。 試想一下,假設呼叫一個非關鍵路徑上的服務(也就是說該呼叫獲取的結果是否實時,是否正確不是特別重要)出現問題,導致呼叫超時、失敗等,在沒有降級措施的情況下,會直接應用服務呼叫方業務。 因此,有些非關鍵路徑上服務呼叫,可以通過服務降級實現有損服務,柔性可用。 開源的降級組件有 Netflix 的 Hystrix,Hystrix 使用比較廣泛。

3.7.2 服務限流

服務降級保護的是服務的呼叫方,也就是服務的依賴方。而服務的提供方呢,如何保證服務的可用性呢? 服務限流指的是對服務呼叫流量的限制,限制其呼叫頻次,來保護服務。在高併發的場景中,很容易出現流量過高,導致服務被打垮。這裡就需要限流來保證服務自身的穩定運行。 Hystrix 也是可以用來限流的,但是用的比較多的有 guava 的 RateLimiter,其使用的是令牌桶演算法,能夠保證平滑限流。

3.7.3 服務隔離

除了服務限流對服務提供方進行保護,就夠了嗎? 可能還不夠,考慮一下這樣的場景,假設某一個有問題的方法出現問題,處理非常耗時,這樣會堵住整個服務處理執行緒,導致正常的服務方法也不能夠正常呼叫。因此還需要服務隔離。 服務隔離指的是對服務執行的方法進行執行緒池隔離,保證異常耗時方法不會對正常的方法呼叫產生干擾,進而保護服務的穩定運行,提升可用性。

3.8 服務監控

服務監控是高可用系統不可或缺的重要支撐。服務監控不僅包括服務呼叫等業務統計信息 Metrics,還包括分佈式鏈路追蹤 Trace。 分佈式系統監控比單體應用要複雜的多,需要將大量的監控信息進行聚合展示,尤其是在分佈式鏈路追蹤方面,由於服務呼叫過程中涉及到多個分佈在不同機器上的服務,需要一個呼叫鏈路展示系統方便查看呼叫鏈路中耗時和出問題的環節。

3.8.1 Metrics

Metrics 監控主要是服務呼叫的一些統計報表,包括服務呼叫次數、成功數、失敗數,以及服務方法的呼叫耗時,如平均耗時,耗時99線,999線等。全方位展示服務的可用性以及性能等信息。 目前開源的 Metrics 監控有美團點評的 Cat、SoundCloud 的 Prometheus 以及基於 OpenTracking 的 SkyWalking。

3.8.2 Trace

Trace 監控是對分佈式服務呼叫過程中的整體鏈路展示和分析。方便查看鏈路上各個環境的性能問題。 分佈式鏈路追蹤的原理大都是基於 Google 的論文 Dapper, a Large-Scale Distributed Systems Tracing Infrastructure。 開源的分佈式鏈路追蹤系統有美團點評的 Cat,基於 OpenTracking 的SkyWalking、Twitter 的 ZipKin。

3.9 配置中心

配置中心不光是常見的系統需要,服務框架也需要,它能夠對系統中使用的配置進行管理,也能夠針對修改配置動態通知到應用系統。 一套完善的服務框架,必然少不了配置,如一些動態開關、降級配置、限流配置、鑒權配置等。 開源的配置中心有阿裡的 Diamond,攜程的 Apollo。

3.10 治理平臺

治理平臺指的是對服務進行管理的平臺。微服務微了之後,必然會導致服務數量的上升,如果沒有一個完善的治理平臺,服務規模擴大之後,很難去維護,也必然導致故障頻頻,並且極度影響開發效率。 治理平臺主要是服務功能的相關操作平臺,包括服務權重修改、服務下線、鑒權降級等配置修改等。 治理平臺跟服務框架的耦合比較強,所以開源的比較少。

4. 總結

一套優秀全面的服務框架,包含各個方面的核心模塊,每個模塊各自展開又是一個細分領域,都可以抽象成單獨的組件。後續文章將會圍繞各個模塊的知識細節進行展開。




如果你對 Dubbo 感興趣,歡迎加入我的知識星球一起交流。

知識星球

目前在知識星球(https://t.zsxq.com/2VbiaEu)更新瞭如下 Dubbo 原始碼解析如下:

01. 除錯環境搭建
02. 專案結構一覽
03. 配置 Configuration
04. 核心流程一覽

05. 拓展機制 SPI

06. 執行緒池

07. 服務暴露 Export

08. 服務取用 Refer

09. 註冊中心 Registry

10. 動態編譯 Compile

11. 動態代理 Proxy

12. 服務呼叫 Invoke

13. 呼叫特性 

14. 過濾器 Filter

15. NIO 服務器

16. P2P 服務器

17. HTTP 服務器

18. 序列化 Serialization

19. 集群容錯 Cluster

20. 優雅停機

21. 日誌適配

22. 狀態檢查

23. 監控中心 Monitor

24. 管理中心 Admin

25. 運維命令 QOS

26. 鏈路追蹤 Tracing


一共 60 篇++

赞(0)

分享創造快樂