Dubbo的設計理念原來就藏在這三張圖中

Dubbo在衆多的微服務框架中脫穎而出,佔據RPC服務框架的半壁江山,很是具備普適性,熟練掌握 Dubbo的應用技巧後深入理解其內部實現原理,讓你們能更好的掌控工做,助力職場,特別能讓你們在面試中脫穎而出。java

那Dubbo內部的設計理念,實現原理是什麼呢?面試

本文將結合官方提供的3張圖,從以下三個方面介紹其內部的核心實現、以及如何指導實踐。算法

一、服務註冊與發現機制

Dubbo的服務註冊與發現機制以下圖所示:
在這裏插入圖片描述
在Dubbo中存在4類角色:編程

  • Registry
    註冊中心。
  • Consumer
    服務調用者、消費端。
  • Provider
    服務提供者。
  • Monitor
    監控中心。

具體的交互流程包括以下關鍵步驟:json

  1. 服務提供者在啓動的時候向註冊中心進行註冊。
  2. 消息消費者在啓動的時候向註冊中心訂閱指定服務,註冊中心將以某種機制(推或拉)模式告知消費端服務提供者列表。
  3. 當服務提供者數量變化(服務提供者擴容、縮容、宕機等因素),註冊中心須要以某種方式(推或拉)告知消費端,以便消費端進行正常的負載均衡。
  4. 服務提供者、服務消費者向監控中心彙報TPS等調用數據,以便監控中心進行可視化展現等。

Dubbo官方提供了多種註冊中心,接下來將以使用最爲廣泛的Zookeeper進一步介紹註冊中心的原理。服務器

首先咱們來看一下Zookeeper註冊中心中的數據存儲目錄結構,從目錄結構來窺探其實現機制。
在這裏插入圖片描述
Dubbo Zookeeper註冊中心,其目錄組織結構爲 /dubbo/{ServiceName},再每個服務名稱下會有4個目錄:網絡

  • providers
    服務提供者列表。
  • consumers
    消費者列表
  • routers
    路由規則列表,關於一個服務能夠設置多個路由規則。
  • configurators
    動態配置條目。在Dubbo中能夠在不重啓消費者、服務提供者的前提下動態修改服務提供者、服務消費者的配置,例如修改線程的數量,超時時間等參數。

基於Zookeeper註冊中心的實現細節以下:多線程

  1. 服務提供者啓動時會向註冊中心註冊,主要是在對應服務的providers目錄下增長一條記錄(臨時節點),同時監聽 configurators節點。
  2. 服務消費者啓動時會向註冊中心訂閱,主要是在對應服務的consumers目錄下增長一條記錄(臨時節點),同時監聽 configurators、routers 目錄。
  3. 因爲當有新的服務提供者上線後 providers 目錄會增長一條記錄,消費者能立馬收到一個服務提供者列表變化的通知,得以將最新的服務提供者列表推送給服務調用方(消費端);若是一個服務提供者宕機,因爲建立的節點是臨時節點,Zookeeper會將該節點移除,一樣會觸發事件,消費端得知最新的服務提供者列表,從而實現路由的動態註冊與發現。
  4. 當Dubbo新版本上線後,若是須要進行灰度發佈,能夠經過dubbo-admin等管理平臺添加路由規則,最終會寫入到指定服務的router節點(持久節點),服務調用方會監聽該節點的變化,從而感知最新的路由規則,將其用於服務提供者的篩選,從而實現灰度發佈等功能。
  5. configurators 節點的運做機制與 router 節點同樣,就不重複介紹。

擴展思考架構

一、若是註冊中心所有宕機,對整個服務體系會有什麼影響?併發

若是整個註冊中心所有宕機,整個服務調用能正常工做,不會影響現有的服務消費者調用,但消費端沒法發現新註冊的服務提供者。

二、若是註冊中心內存溢出或頻繁發生 Full Gc,對整個集羣又會帶來什麼影響呢?

若是頻繁發生Full GC,而且若是Full GC的時間超過了Zookeeper會話的過時時間,將會形成很是嚴重的影響,會觸發全部臨時節點被刪除,消費端將沒法感知服務提供者的存在,影響服務調用,將大面積拋出 No provider 等錯誤。正所謂成也臨時節點、敗也臨時節點

爲了不Full Gc帶來的嚴重後果,用於Dubbo註冊中心的Zookeeper,必定會要獨享,並及時作好內存、CPU等的監控與告警。

二、服務調用

Dubbo的服務調用設計十分優雅,其實現原理以下圖所示:
在這裏插入圖片描述
服務調用,重點闡述客戶端發起一個RPC服務調用時的全部實現細節,包括服務發現故障轉移路由轉發負載均衡等方面,是Dubbo實現灰度發佈的理論基礎。

2.1 服務發現

客戶端在向服務端發起請求時,首先須要知道的是當前有哪些可用的服務提供者,一般有兩種服務發現機制:

  • 靜態化配置
    不妨回想一下,在Dubbo等微服務框架出現以前,一個模塊調用另一個模塊一般的作法是使用一個配置文件,將服務提供的列表配置配置在配置文件中,客戶端從按照配置文件中的列表進行淪陷。

    弊端也很是明顯:若是須要調用的服務衆多,配置文件會變得臃腫,對擴容縮容的管理、機器宕機等變動不友好,管理很是困難。

  • 動態發現

    一般基於註冊中心實現服務的註冊與動態發現,因爲上文已詳細介紹,在這裏就不累述。

2.2 負載均衡

客戶端經過服務發現機制,能動態發現當前存活的服務提供者列表,接下來要考慮的是若是從服務提供者列表中選擇一個服務提供者發起調用,這就是所謂的負載均衡,即 LoadBalance。

在Dubbo中默認提供了隨機、加權隨機、最少活躍鏈接、一致性Hash等負載均衡算法。

2.3 路由機制

其實Dubbo中不只提供了負載均衡機制,還提供了智能路由機制,這是實現Dubbo灰度發佈的理論基礎。

所謂的路由機制,是在服務提供者列表中,再設置必定的規則,進行過濾選擇,負載均衡時只從路由過濾規則篩選出來的服務提供者列表中選擇,爲了更加形象的闡述路由機制的工做原理,給出以下示意圖:
在這裏插入圖片描述
上述設置了一條路由規則,即查詢機構ID爲102的查詢用戶請求信息,請發送到新版本,即192168.3.102上,那主要在進行負載均衡以前先執行路由規則,從原始的服務提供者列表者按照路由規則進行過濾,從中挑選出符合要求的提供者列表,而後再進行負載均衡。

路由機制的核心理念:在進行負載均衡以前先對服務提供者列表運用路由規則,得出一個參與負載均衡的提供者列表。

2.4 故障轉移

遠程服務調用一般涉及到網絡等因素,客戶端向服務提供者發起RPC請求調用時並不必定100%成功,當調用失敗後該採用何種策略呢?

Dubbo提供了以下策略:

  • failover
    失敗後選擇另一臺服務提供者進行重試,重試次數可配置,一般適合實現冪等服務的場景

  • failfast

    快速失敗,失敗後當即返回錯誤。

  • failsafe
    調用失敗後打印錯誤日誌,返回成功,一般用於記錄審計日誌等場景

  • failback
    調用失敗後,返回成功,但會在後臺定時無限次重試,重啓後再也不重試。

  • forking
    併發調用,收到第一個響應結果後返回給客戶端。一般適合實時性要求比較高的場景,但浪費服務器資源,一般能夠經過forks參數設置併發調用度。

三、線程派發機制

Dubbo的通訊線程模型入下圖所示:
在這裏插入圖片描述

3.1 網絡通訊協議

網絡傳輸一般須要自定義通訊協議,一般採用 Header + Body 的協議設計理念,而且 Header 長度固定,而且包含一個長度字段,用於記錄整個協議包的大小。

網絡傳輸爲了提升傳輸效率,能夠採起對傳輸數據進行壓縮,一般是對 body 進行序列化與壓縮。

Dubbo支持目前支持 java、compactedjava、nativejava、fastjson、fst、hessian二、kryo等序列化協議。

3.2 線程派發機制

在Dubbo中默認會建立200個線程用於處理業務方法,所謂的線程派發機制就是IO線程如何決定何種請求轉發到哪類線程中執行。

目前Dubbo中全部的心跳包、網絡讀寫在IO線程中執行,沒法經過配置進行修改。

Dubbo提供了以下幾種線程派發機制(Dispatcher):

  • all
    全部的請求轉發到業務線程池中執行(除IO讀寫、心跳包)

  • message
    只有請求事件在線程池中執行,其餘在IO線程上執行。

  • connection
    請求事件在線程池中執行,鏈接、斷開鏈接事件排隊執行(含一個線程的線程池)

  • direct

    全部請求直接在IO線程中執行。

舒適提示:有關線程模型,網絡通訊模式,能夠參考筆者以下這篇文章。

線程派發機制之全部會有多種策略,主要是考慮線程切換帶來的開銷是否能容忍,即線程切換帶來的開銷小於多線程處理帶來的提高。

例如在Dubbo中,對心跳包只需直接返回PONG包(OK),邏輯很是簡單,若是將其轉換到業務線程池,並不能帶來性能提高,反而由於須要線程切換,帶來性能損耗,故在IO線程中直接發送響應包是一個很是可取的作法。

在網絡編程中須要遵循一條最佳實踐IO線程中不能有阻塞操做,阻塞操做須要轉發到業務線程池


好了,本文就介紹到這裏了,您的點贊與轉發是對我持續輸出高質量文章最大的鼓勵。

歡迎關注公衆號『中間件興趣圈』,共同探究源碼,交流高併發、架構經驗,回覆 PDF 更是可獲取大量學習資料。

相關文章
相關標籤/搜索