分佈式服務架構設計概述 分佈式服務框架設計架構原理

分佈式服務框架設計架構原理

通常,分佈式服務框架的架構可以抽象爲三層:


  1. RPC層:包括底層通信框架(例如NIO框架的封裝、公有協議的封裝等)、序列化和反序列化框架、用於屏蔽底層通信協議細節和序列化方式差異的Remoting框架。
  2. Filter Chain層:服務調用職責鏈,提供多種服務調用切面供框架自身和使用者擴展,例如負載均衡、服務調用性能統計、服務調用完成通知機制、失敗重發等等。
  3. Service層:主要包括Java動態代理。消費者使用,主要用於將服務提供者的接口封裝成遠程服務調用:Java反射。服務提供者使用,根據消費者請求消息中的接口名、方法名、參數列表反射調用服務提供者的接口本地實現類。再向上就是業務的服務接口定義和實現類。

從功能角度來看,分佈式服務框架通常會包含另外兩個重要功能:服務治理中心和服務註冊中心,業務需求不同,具體實現細節也會有很大的差異,比如HSF使用的服務註冊中心是基於數據庫的ConfigServer,Dubbo默認使用的是Zookeeper。

服務註冊中心:負責服務的發佈和通知。
服務治理中心:通常包含服務治理接口和服務治理Portal。

通信框架

長連接還是短鏈接

絕大多數分佈式服務框架(RPC框架)都推薦長連接,因爲相比短鏈接,長連接更節省資源,如果每發一條消息,都要創建鏈路、握手、關閉鏈路釋放資源,會消耗大量系統資源。因爲遠程通信中調用時延是關鍵指標:服務化後,本地API調用變成了遠程服務調用,鏈路層的時延消耗遠遠大於服務調用本身的損耗。

BIO還是NIO

在JDK1.4推出Java NIO之前,基於Java的所有Socket通信都採用了同步阻塞模式(BIO),這種一請求以應答的通信模式簡化了上層的應用開發,但是在性能和可靠性方面卻存在着巨大的瓶頸。
NIO採用多路複用技術,一個多路複用器Selector可以同時輪詢多個Channel。

隨着開源NIO框架的發展,例如Hadoop的RPC框架和實時流式計算框架Storm使用Netty作爲底層通信框架。

序列化與反序列化

序列化與通信框架不是強耦合的關係,通信框架提供的編碼、解碼可以非常方便的支持用戶通過拓展實現自定義的序列化格式。用戶也可以在應用程序及其他位置實現對象的序列化和反序列化。通信框架提供的編碼、解碼接口可以作爲可選項,並不強制用戶一定要在通信框架內部實現消息的序列化和反序列化。

協議棧

不同服務在性能上適用於不同的協議進行傳輸,比如對接異構第三方服務的時候,通常會選擇HTTP/Restful 等公有協議;對內部不用模塊之間的服務調用,往往會選擇性能較高的二進制私有協議。

大部分服務框架都支持多協議,但多協議不是必須的。如果是開源的分佈式服務框架,會考慮協議的通用性,一般會採用例如Web Service 和HTTP之類的協議。

服務路由

分佈式服務框架運行時都是集羣組網,這意味着集羣中存在某個服務的多個實例的部署。消費者如何選取最佳實例,這就涉及到服務的路由。

基於服務註冊中心的訂閱發佈

透明化路由
很多開源的RPC框架調用者需要配置服務提供者的地址信息,儘管可以通過讀取數據庫的服務地址列表等避免硬編碼地址信息,但是消費者仍然要感知服務提供者的地址信息,這違反了透明化路由的原則。

在分佈式服務框架中,服務註冊中心用於存儲服務提供者的地址信息、服務發佈相關的屬性信息。
消費者通過主動查詢和被動通知兩種方式來獲取服務提供者的地址信息,而不需要硬編碼地址信息,消費者只需要知道服務,不需要知道服務提供者的位置,這就是透明化路由。

透明化路由的工作原理就是基於服務註冊中心的訂閱發佈機制(例如Zookeeper)。



在該機制下,消費者和提供者與服務註冊中心建立鏈路(如ZK建立的長連接)。

負載均衡

  1. 隨機
    採用隨機算法實現負載均衡,通常在對等集羣組網中,隨機路由算法消息分發還是比較均勻的,它的缺點主要是:如果是非對等集羣組網,或者硬件配置差異打,會導致各個節點負載不均衡。
  2. 輪詢
    按照權重輪詢服務提供者列表。
  3. 服務調用時延
    週期性的計算服務調用的平均時延,然後根據每個服務者的調用時延與平均時延的差值重新設計權重,保障服務時延小的接收更多的信息,防止消息堆積。
  4. 一致性哈希
    一致性哈希在我以前的博客中提到過,不做贅述。

集羣容錯

集羣服務調用失敗後,服務框架需要能夠在底層自動容錯。下面介紹幾種容錯策略:

  1. 失敗自動切換(Failover)
    服務調用失敗自動切換策略指的是當發生RPC調用異常時,重新選路,查找下一個可用的服務提供者。
  2. 失敗通知(Failback)
    在有些業務場景下,消費者需要知道服務調用失敗的具體信息,以決定後續執行策略,如非冪等性的服務調用。
  3. 失敗緩存(Failcache)
    失敗緩存是失敗自動恢復的一種,如果重試達到上限仍然失敗,則需要丟棄消息,記錄一場日誌。該方法適合對時延要求不敏感。
  4. 快速失敗(Failfast)
    在業務高峯期,對於一些非核心業務,希望只調用一次,即使失敗也不重試,爲其他核心服務節約運行資源。

服務降級

在大促或者業務高峯時,爲了保證核心服務的SLA,往往需要停掉或者強制降級一些不太重要的服務,比如商品評論或者用戶積分等等。

對非核心服務做強制降級,不發器遠程服務調用,直接返回空、異常或者執行特定的本地邏輯,減少自身對公共資源的消費,把資源釋放出來供核心服務使用。
屏蔽降級流程如下:


分佈式消息跟蹤

隨着業務分佈式架構的發展,一個功能的實現往往涉及到底層上百次的服務調用,涉及到的中間件可能包括分佈式服務框架、消息隊列、分佈式緩存、分佈式文件存儲系統、分佈式日誌採集等等,如果無法有效理清後端分佈式調用和依賴關係,故障定位將非常困難。

在傳統應用軟件發生故障時,往往通過接口日誌手工從故障節點採集日誌進行問題分析定位,分佈式服務化之後,一次業務調用可能涉及到後臺上百次服務調用,每個服務又是集羣組網,這樣效率會很慢。

如果利用調用鏈進行快速故障界定,通過在業務日誌中增加調用鏈ID,可以實現業務日誌和調用鏈的動態關聯。

通過對調用鏈和調用路徑的分析,可以識別應用的關鍵路徑,如下圖所示:



通過調用去向分析,可以對服務的依賴關係進行梳理:

  1. 應用直接和間接依賴了哪些服務。
  2. 更層次依賴的調用時延、QPS、成功率等性能KPI指標。
  3. 識別不合理的強依賴或者冗餘依賴。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章