主頁 > 軟體設計 > Dubbo架構理解

Dubbo架構理解

2021-02-06 10:59:09 軟體設計

Dubbo架構理解

架構整體設計

Dubbo呼叫關系說明

image.png
在這里主要由四部分組成:

  • Provider: 暴露服務的服務提供方

Protocol 負責提供者和消費者之間協議互動資料
Service 真實的業務服務資訊 可以理解成介面 和 實作
Container Dubbo的運行環境

  • Consumer: 呼叫遠程服務的服務消費方

Protocol 負責提供者和消費者之間協議互動資料
Cluster 感知提供者端的串列資訊
Proxy 可以理解成 提供者的服務呼叫代理類,由它接管 Consumer 中的介面呼叫邏輯

  • Registry: 注冊中心,用于作為服務發現和路由配置等作業,提供者和消費者都會在這里進行注冊
  • Monitor: 用于提供者和消費者中的資料統計,比如呼叫頻次,成功失敗次數等資訊,

啟動和執行流程說明:

  1. 提供者端啟動 容器負責把Service資訊加載 并通過Protocol 注冊到注冊中心
  2. 消費者端啟動 通過監聽提供者串列來感知提供者資訊 并在提供者發生改變時 通過注冊中心及時,通知消費端
  3. 消費方發起請求通過Proxy模塊
  4. 利用Cluster模塊 來選擇真實的要發送給的提供者資訊
  5. 交由Consumer中的Protocol 把資訊發送給提供者
  6. 提供者同樣需要通過 Protocol 模塊來處理消費者的資訊
  7. 最后由真正的服務提供者 Service 來進行處理

整體的呼叫鏈路

image.png
業務邏輯層 RPC層(遠程程序呼叫) Remoting (遠程資料傳輸)
整體鏈路呼叫的流程:

  1. 消費者通過Interface進行方法呼叫 統一交由消費者端的 Proxy 通過ProxyFactory 來進行代理物件的創建 使用到了 jdk javassist技術
    2.交給Filter 這個模塊 做一個統一的過濾請求 在SPI案例中涉及過
    3.接下來會進入最主要的Invoker呼叫邏輯
    通過Directory 去配置中心讀取資訊 最終通過list方法獲取所有的Invoker
    通過Cluster模塊 根據選擇的具體路由規則 來選取Invoker串列
    通過LoadBalance模塊 根據負載均衡策略 選擇一個具體的Invoker 來處理請求
    如果執行中出現錯誤 并且Consumer階段配置了重試機制 則會重新嘗試執行
  2. 繼續經過Filter 進行執行功能的前后封裝 Invoker 選擇具體的執行協議
  3. 客戶端 進行編碼和序列化 然后發送資料
  4. 到達Provider中的 Server 在這里進行 反編碼 和 反序列化的接收資料
  5. 使用Exporter選擇執行器
  6. 交給Filter 進行一個提供者端的過濾 到達 Invoker 執行器
  7. 通過Invoker 呼叫介面的具體實作 然后回傳

Dubbo原始碼整體設計

image.png
右邊的黑色箭頭代表層之間的依賴關系,每一層都可以剝離上層被復用,其中,Service 和 Config 層為 API,其它各層均為 SPI,

分層介紹:
Business 業務邏輯層

  • service 業務層 包括業務代碼 比如 介面 實作類 直接面向開發者

RPC層 遠程程序呼叫層

  • config 配置層 對外提供配置 以ServiceConfig ReferenceConfig 為核心 可以直接初始化配置類 也可以決議組態檔生成
  • proxy 服務代理層 無論是生產者 還是消費者 框架都會產生一個代理類 整個程序對上層透明 就是業務層對遠程呼叫無感
  • registry 注冊中心層 封裝服務地址的注冊與發現 以服務的URL為中心
  • cluster 路由層 (集群容錯層) 提供了多個提供者的路由和負載均衡 并且它橋接注冊中心 以Invoker為核心
  • monitor 監控層 RPC呼叫相關的資訊 如 呼叫次數 成功失敗的情況 呼叫時間等 在這一層完成
  • protocol 遠程呼叫層 封裝RPC呼叫 無論是服務的暴露 還是 服務的參考 都是在Protocol中作為主功能入口 負責Invoker的整個生命周期 Dubbo中所有的模型都向Invoker靠攏

Remoting層 遠程資料傳輸層

  • exchange 資訊交換層 封裝請求和回應的模式 如把請求由同步 轉換成異步
  • transport 網路傳輸層 統一網路傳輸的介面 比如 netty 和 mina 統一為一個網路傳輸介面
  • serialize 資料序列化層 負責管理整個框架中的資料傳輸的序列化 和反序列化

服務注冊與消費原始碼剖析

image.png

注冊中心Zookeeper目錄結構

例如:只有一個提供者和消費者, com.lagou.service.HelloService 為我們所提供的服務,
image.png
Zookeeper的目錄結構如下:
image.png

  • consumers: 當前服務下面所有的消費者串列(URL)
  • providers: 當前服務下面所有的提供者串列(URL)
  • configuration: 當前服務下面的配置資訊資訊,provider或者consumer會通過讀取這里的配置資訊來獲取配置
  • routers: 當消費者在進行獲取提供者的時,會通過這里配置好的路由來進行適配匹配規則,

image.png

  • 提供者會在 providers 目錄下進行自身的進行注冊,
  • 消費者會在 consumers 目錄下進行自身注冊,并且監聽 provider 目錄,以此通過監聽提供者增加或者減少,實作服務發現,
  • Monitor模塊會對整個服務級別做監聽,用來得知整體的服務情況,以此就能更多的對整體情況做監控,

服務的注冊程序分析

服務注冊(暴露)程序
image.png
首先 ServiceConfig 類拿到對外提供服務的實際類 ref(具體的介面實作類),然后通過 ProxyFactory 介面實作類中的 getInvoker 方法使用 ref 生成一個 AbstractProxyInvoker 實體,到這一步就完成具體服務到 Invoker 的轉化,接下來就是 Invoker 轉換到 Exporter 的程序,

查看 ServiceConfifig 類,重點查看 ProxyFactory 和 Protocol 型別的屬性 以及 ref


服務注冊暴露時序圖:
image.png
Registry中的類目錄結構
image.png

  • 每個層級代表繼承自父級
  • 這里面 RegistryService 就是對外提供注冊機制的介面,
  • 其下面 Registry 也同樣是一個介面,是對 RegistryService 的集成,并且繼承了 Node 介面,說明注冊中心也是基于URL去做的,
  • AbstractRegistry 是對注冊中心的封裝,其主要會對本地注冊地址的封裝,主要功能在于遠程注冊中心不可用的時候,可以采用本地的注冊中心來使用,
  • FailbackRegistry 從名字中可以看出來,失敗自動恢復,后臺記錄失敗請求,定時重發功能,
  • 最深的一層則更多是真實的第三方渠道實作,

URL規則詳解 和 服務本地快取

URL規則詳解

image.png

服務本地快取

dubbo呼叫者需要通過注冊中心(例如:ZK)注冊資訊,獲取提供者,但是如果頻繁往從ZK獲取資訊,肯定會存在單點故障問題,所以dubbo提供了將提供者資訊快取在本地的方法,
Dubbo在訂閱注冊中心的回呼處理邏輯當中會保存服務提供者資訊到本地快取檔案當中(同步/異步兩種方式),以URL緯度進行全量保存,
Dubbo在服務參考程序中會創建registry物件并加載本地快取檔案,會優先訂閱注冊中心,訂閱注冊中心失敗后會訪問本地快取檔案內容獲取服務提供資訊,

構建流程:

  1. 初始化AbstractRegistry建構式,并且從系統中讀取已有的配置資訊,

image.png

  1. 方法notify(url.getBackupUrls()) ->notify(url, listener, filterEmpty(url, urls)) -> saveProperties(url),通過尋找,這個屬性的設定值只有在一個地方: saveProperties ,這里也有基于版本號的的更改

image.png

  1. doSaveProperties(long version),最終快取的保存方法,

未標題-1.jpg

Dubbo 消費程序分析

image.png
首先 ReferenceConfig 類的 init 方法呼叫 createProxy() ,期間 使用 Protocol 呼叫 refer 方法生 成 Invoker 實體(如上圖中的紅色部分),這是服務消費的關鍵,接下來使用ProxyFactory把 Invoker 轉換為客戶端需要的介面
image.png

Dubbo擴展SPI原始碼剖析

getExtensionLoader 加載程序

image.png
注:

  • cachedAdaptiveClass: 當前Extension型別對應的AdaptiveExtension型別(只能一個)
  • cachedWrapperClasses: 當前Extension型別對應的所有Wrapper實作型別(無順序)
  • cachedActivates: 當前Extension實作自動激活實作快取(map,無序)
  • cachedNames: 擴展點實作類對應的名稱(如配置多個名稱則值為第一個)
  • **getExtension獲取擴展點的方法 **
  • injectExtension注入其他擴展點的物體,用于擴展點和其他的擴展點相互打通(set的方式注入)

Adaptive功能實作原理

Adaptive的主要功能是對所有的擴展點進行封裝為一個類,通過URL傳入引數的時動態選擇需要使用的擴展點,其底層的實作原理就是動態代理,
image.png
createAdaptiveExtensionClass()方法生成具體的Adaptive代理物件,通過AdaptiveClassCodeGenerator下的generate()方法做將具體的介面實作類重新做字串拼接插入需要提前呼叫的方法和URL引數判斷,最后通過org.apache.dubbo.common.compiler.Compiler 將字串編譯成class檔案,

private Class<?> createAdaptiveExtensionClass() {
    String code = new AdaptiveClassCodeGenerator(type, cachedDefaultName).generate();
    ClassLoader classLoader = findClassLoader();
    org.apache.dubbo.common.compiler.Compiler compiler = 	
        ExtensionLoader.getExtensionLoader(org.apache.dubbo.common.compiler.Compiler.class)
        .getAdaptiveExtension();
    return compiler.compile(code, classLoader);
}

**

集群容錯原始碼剖析

集群容錯的組件包含 Cluster、 Cluster Invoker、Directory、Router 和 LoadBalance 等,
image.png
集群作業程序可分為兩個階段:

  • 第一個階段是在服務消費者初始化期間,集群 Cluster 實作類為服務消 費者創建 Cluster Invoker 實體,即上圖中的 merge 操作,
  • 第二個階段是在服務消費者進行遠程呼叫時,以FailoverClusterInvoker為例:
    1. 該型別ClusterInvoker首先會呼叫Directory的list方法列舉Invoker串列(可將Invoker簡單理解為服務提供者),Directory的用途是保存Invoker串列,可簡單類比為List,其實作類RegistryDirectory是一個動態服務目錄,可感知注冊中心配置的變化,它所持有的Invoker串列會隨著注冊中心內容的變化而變化,
    2. 每次變化后,RegistryDirectory會動態增刪Invoker,并呼叫Router的route方法進行路由,過濾掉不符合路由規則的Invoker,
    3. 當FailoverClusterInvoker拿到Directory回傳的Invoker串列后,它會通過LoadBalance從Invoker串列中選擇一個Invoker,
    4. 最后FailoverClusterInvoker會將引數傳給LoadBalance選擇出的Invoker實體的invoker方法,進行真正的遠程呼叫,

Dubbo 主要提供了這樣幾種容錯方式:

  1. Failover Cluster - 失敗自動切換 失敗時會重試其它服務器
  2. Failfast Cluster - 快速失敗 請求失敗后快速回傳例外結果 不重試
  3. Failsafe Cluster - 失敗安全 出現例外 直接忽略 會對請求做負載均衡
  4. Failback Cluster - 失敗自動恢復 請求失敗后 會自動記錄請求到失敗佇列中
  5. Forking Cluster - 并行呼叫多個服務提供者 其中有一個回傳 則立即回傳結果

資訊快取介面Directory

Directory是Dubbo中的一個介面,主要用于快取當前可以被呼叫的提供者串列資訊,我們在消費者進 行呼叫時都會通過這個介面來獲取所有的提供者串列,再進行后續處理,

public interface Directory<T> extends Node {
	//獲取服務型別
    Class<T> getInterface();
    //獲取本次呼叫可以使用的提供者資訊
    List<Invoker<T>> list(Invocation invocation) throws RpcException;
    //獲取所有提供者資訊
    List<Invoker<T>> getAllInvokers();

    URL getConsumerUrl();
}

image.pngRouterChain#route 方法,這里所做的就是依次遍歷所有的路由,然后分別執行并回傳,這 也就是整體的路由規則的實作,
image.png

路由規則實作原理

RouterChain 中的 Router下的子類 ConditionRouter 為例image.png
這兩個屬性比較關鍵,這兩個屬性也是判斷的關鍵,
image.png
init方法做路由規則的初始化,也對上面的whenCondition與thenCondition做了初始化,其中paseRule方法是決議路由規則的方法并回傳Map其值MatchPair存盤了匹配條件和不匹配條件的Set集合
image.png
MatchPair
image.png
route方法則是篩選出符合條件的invoke并進行回傳(List)
222.jpg

Cluster組件

Cluster 主要用于代理真正的Invoker執行時做處理,提供了多種容錯方案,
image.png
這里以默認的FailoverCluster為例
image.png
image.png
通過 AbstractClusterInvoker#invoke 呼叫 FailoverClusterInvoker#doInvoke
image.png
image.png
1111.jpg

負載均衡實作原理

Cluster 中經過負載選擇真正 Invoker 的代碼
image.png
以RandomLoadBalance為例,doSelect負責處理具體的負載均衡操作,
image.png

Invoker執行邏輯

Invoker是真實執行請求的組件,
image.png
以DubboInvoker呼叫為例
image.png
ExchangeClient為主要資料傳輸的客戶端,其繼承了HeaderExchangeChannel介面
image.png
doInvoke方法中根據isOneway判斷是否執行異步請求
image.png
ExchangeClient 介面下的 **request **方法為真實發送訊息的方法
image.png

轉載請註明出處,本文鏈接:https://www.uj5u.com/ruanti/257081.html

標籤:其他

上一篇:部署ceph集群架構+Dashboard出圖

下一篇:優化Kubernetes集群內DNS

標籤雲
其他(157675) Python(38076) JavaScript(25376) Java(17977) C(15215) 區塊鏈(8255) C#(7972) AI(7469) 爪哇(7425) MySQL(7132) html(6777) 基礎類(6313) sql(6102) 熊猫(6058) PHP(5869) 数组(5741) R(5409) Linux(5327) 反应(5209) 腳本語言(PerlPython)(5129) 非技術區(4971) Android(4554) 数据框(4311) css(4259) 节点.js(4032) C語言(3288) json(3245) 列表(3129) 扑(3119) C++語言(3117) 安卓(2998) 打字稿(2995) VBA(2789) Java相關(2746) 疑難問題(2699) 细绳(2522) 單片機工控(2479) iOS(2429) ASP.NET(2402) MongoDB(2323) 麻木的(2285) 正则表达式(2254) 字典(2211) 循环(2198) 迅速(2185) 擅长(2169) 镖(2155) 功能(1967) .NET技术(1958) Web開發(1951) python-3.x(1918) HtmlCss(1915) 弹簧靴(1913) C++(1909) xml(1889) PostgreSQL(1872) .NETCore(1853) 谷歌表格(1846) Unity3D(1843) for循环(1842)

熱門瀏覽
  • 面試突擊第一季,第二季,第三季

    第一季必考 https://www.bilibili.com/video/BV1FE411y79Y?from=search&seid=15921726601957489746 第二季分布式 https://www.bilibili.com/video/BV13f4y127ee/?spm_id_fro ......

    uj5u.com 2020-09-10 05:35:24 more
  • 第三單元作業總結

    1.前言 這應該是本學期最后一次寫作業總結了吧。總體來說,對作業的節奏也差不多掌握了,作業做起來的效率也更高了。雖然和之前的作業一樣,作業中都要用到新的知識,但是相比之前,更加懂得了如何利用工具以及資料。雖然之間卡過殼,但總體而言,這幾次作業還算完成的比較好。 2.作業程序總結 相比前兩個單元,此單 ......

    uj5u.com 2020-09-10 05:35:41 more
  • 北航OO(2020)第四單元博客作業暨課程總結博客

    北航OO(2020)第四單元博客作業暨課程總結博客 本單元作業的架構設計 在本單元中,由于UML圖具有比較清晰的樹形結構,因此我對其中需要進行查詢操作的元素進行了包裝,在樹的父節點中存盤所有孩子的參考。考慮到性能問題,我采用了快取機制,一次查詢后盡可能快取已經遍歷過的資訊,以減少遍歷次數。 本單元我 ......

    uj5u.com 2020-09-10 05:35:48 more
  • BUAA_OO_第四單元

    一、UML決議器設計 ? 先看下題目:第四單元實作一個基于JDK 8帶有效性檢查的UML(Unified Modeling Language)類圖,順序圖,狀態圖分析器 MyUmlInteraction,實際上我們要建立一個有向圖模型,UML中的物件(元素)可能與同級元素連接,也可與低級元素相連形成 ......

    uj5u.com 2020-09-10 05:35:54 more
  • 6.1邏輯運算子

    邏輯運算子 1. && 短路與 運算式1 && 運算式2 01.運算式1為true并且運算式2也為true 整體回傳為true 02.運算式1為false,將不會執行運算式2 整體回傳為false 03.只要有一個運算式為false 整體回傳為false 2. || 短路或 運算式1 || 運算式2 ......

    uj5u.com 2020-09-10 05:35:56 more
  • BUAAOO 第四單元 & 課程總結

    1. 第四單元:StarUml檔案決議 本單元采用了圖模型決議UML。 UML檔案可以抽象為圖、子圖、邊的邏輯結構。 在實作中,圖的節點包括類、介面、屬性,子圖包括狀態圖、順序圖等。 采用了三次遍歷UML元素的方法建圖,第一遍遍歷建點,第二、三次遍歷設定屬性、連邊,實作圖物件的初始化。這里借鑒了一些 ......

    uj5u.com 2020-09-10 05:36:06 more
  • 談談我對C# 多型的理解

    面向物件三要素:封裝、繼承、多型。 封裝和繼承,這兩個比較好理解,但要理解多型的話,可就稍微有點難度了。今天,我們就來講講多型的理解。 我們應該經常會看到面試題目:請談談對多型的理解。 其實呢,多型非常簡單,就一句話:呼叫同一種方法產生了不同的結果。 具體實作方式有三種。 一、多載 多載很簡單。 p ......

    uj5u.com 2020-09-10 05:36:09 more
  • Python 資料驅動工具:DDT

    背景 python 的unittest 沒有自帶資料驅動功能。 所以如果使用unittest,同時又想使用資料驅動,那么就可以使用DDT來完成。 DDT是 “Data-Driven Tests”的縮寫。 資料:http://ddt.readthedocs.io/en/latest/ 使用方法 dd. ......

    uj5u.com 2020-09-10 05:36:13 more
  • Python里面的xlrd模塊詳解

    那我就一下面積個問題對xlrd模塊進行學習一下: 1.什么是xlrd模塊? 2.為什么使用xlrd模塊? 3.怎樣使用xlrd模塊? 1.什么是xlrd模塊? ?python操作excel主要用到xlrd和xlwt這兩個庫,即xlrd是讀excel,xlwt是寫excel的庫。 今天就先來說一下xl ......

    uj5u.com 2020-09-10 05:36:28 more
  • 當我們創建HashMap時,底層到底做了什么?

    jdk1.7中的底層實作程序(底層基于陣列+鏈表) 在我們new HashMap()時,底層創建了默認長度為16的一維陣列Entry[ ] table。當我們呼叫map.put(key1,value1)方法向HashMap里添加資料的時候: 首先,呼叫key1所在類的hashCode()計算key1 ......

    uj5u.com 2020-09-10 05:36:38 more
最新发布
  • 【中介者設計模式詳解】C/Java/JS/Go/Python/TS不同語言實作

    * 中介者模式是一種行為型設計模式,它可以用來減少類之間的直接依賴關系,
    * 將物件之間的通信封裝到一個中介者物件中,從而使得各個物件之間的關系更加松散。
    * 在中介者模式中,物件之間不再直接相互互動,而是通過中介者來中轉訊息。 ......

    uj5u.com 2023-04-20 08:20:47 more
  • 露天煤礦現場調研和交流案例分享

    他們集團的資訊化公司及研究院在一個礦區正在做智能礦山的統一平臺的 試點,專案投資大概1億,包括了礦山的各方面的內容,顯示得我們這次交流有點多余。他們2年前開始做智能礦山的規劃,有很多煤礦行業專家的加持,他們的描述是非常完美,但是去年底應該上線的平臺,現在還沒有看到影子。他們確實有很多場景需求,但是被... ......

    uj5u.com 2023-04-20 08:20:25 more
  • 《社區人員管理》實戰案例設計&個人案例分享

    設計是一個讓人夢想成真程序,開始編碼、測驗、除錯之前進行需求分析和架構設計,才能保證關鍵方面都做正確 ......

    uj5u.com 2023-04-20 08:20:17 more
  • 軟體架構生態化-多角色交付的探索實踐

    作為一個技術架構師,不僅僅要緊跟行業技術趨勢,還要結合研發團隊現狀及痛點,探索新的交付方案。在日常中,你是否遇到如下問題 “ 業務需求排期長研發是瓶頸;非研發角色感受不到研發技改提效的變化;引入ISV 團隊又擔心質量和安全,培訓周期長“等等,基于此我們探索了一種新的技術體系及交付方案來解決如上問題。 ......

    uj5u.com 2023-04-20 08:20:10 more
  • 【中介者設計模式詳解】C/Java/JS/Go/Python/TS不同語言實作

    * 中介者模式是一種行為型設計模式,它可以用來減少類之間的直接依賴關系,
    * 將物件之間的通信封裝到一個中介者物件中,從而使得各個物件之間的關系更加松散。
    * 在中介者模式中,物件之間不再直接相互互動,而是通過中介者來中轉訊息。 ......

    uj5u.com 2023-04-20 08:19:44 more
  • 露天煤礦現場調研和交流案例分享

    他們集團的資訊化公司及研究院在一個礦區正在做智能礦山的統一平臺的 試點,專案投資大概1億,包括了礦山的各方面的內容,顯示得我們這次交流有點多余。他們2年前開始做智能礦山的規劃,有很多煤礦行業專家的加持,他們的描述是非常完美,但是去年底應該上線的平臺,現在還沒有看到影子。他們確實有很多場景需求,但是被... ......

    uj5u.com 2023-04-20 08:19:07 more
  • 《社區人員管理》實戰案例設計&個人案例分享

    設計是一個讓人夢想成真程序,開始編碼、測驗、除錯之前進行需求分析和架構設計,才能保證關鍵方面都做正確 ......

    uj5u.com 2023-04-20 08:18:57 more
  • 軟體架構生態化-多角色交付的探索實踐

    作為一個技術架構師,不僅僅要緊跟行業技術趨勢,還要結合研發團隊現狀及痛點,探索新的交付方案。在日常中,你是否遇到如下問題 “ 業務需求排期長研發是瓶頸;非研發角色感受不到研發技改提效的變化;引入ISV 團隊又擔心質量和安全,培訓周期長“等等,基于此我們探索了一種新的技術體系及交付方案來解決如上問題。 ......

    uj5u.com 2023-04-20 08:18:49 more
  • 05單件模式

    #經典的單件模式 public class Singleton { private static Singleton uniqueInstance; //一個靜態變數持有Singleton類的唯一實體。 // 其他有用的實體變數寫在這里 //構造器宣告為私有,只有Singleton可以實體化這個類! ......

    uj5u.com 2023-04-19 08:42:51 more
  • 【架構與設計】常見微服務分層架構的區別和落地實踐

    軟體工程的方方面面都遵循一個最基本的道理:沒有銀彈,架構分層模型更是如此,每一種都有各自優缺點,所以請根據不同的業務場景,并遵循簡單、可演進這兩個重要的架構原則選擇合適的架構分層模型即可。 ......

    uj5u.com 2023-04-19 08:42:41 more