大家好,我是小羽。
Dubbo 起源於阿里巴巴,對於我們做電商開發的人來說,基本是首選的技術,那麼為何一個區區 soa 服務治理框架,會受到這麼多人的青睞呢?
今天就跟著小羽一起看看這個微服務框架之一的 Dubbo 的詳細解讀吧。
前言
網際網路的不斷髮展,網站應用的規模不斷擴大,常規的垂直應用架構已無法應對。
服務化的進一步發展,服務越來越多,服務之間的呼叫和依賴關係也越來越複雜,誕生了面向服務的架構體系(SOA),
也因此衍生出了一系列相應的技術,如對服務提供、服務呼叫、連線處理、通訊協議、序列化方式、服務發現、服務路由、日誌輸出等行為進行封裝的服務框架。
就這樣分散式系統的服務治理框架就出現了,Dubbo也就這樣產生了。
概念
Dubbo 是一款高效能、輕量級的開源 RPC
框架、提供服務自動註冊、自動發現等高效治理方案,可以和 Spring
框架無縫整合。
簡單的說,dubbo就是個分散式服務框架,在有分散式需要的時候可以使用 dubbo 的框架,使用 dubbo 的好處:
_1、_透明化的遠端方法呼叫
_2、_軟負載均衡及容錯機制
_3、_服務自動註冊與發現
_4、_提供了完善的服務介面管理與監控功能
架構圖
RPC
簡介
RPC 全稱為 remote procedure call,即遠端過程呼叫。比如兩臺伺服器 A 和 B,A 伺服器上部署一個應用,B 伺服器上部署一個應用,A 伺服器上的應用想呼叫 B 伺服器上的應用提供的方法,由於兩個應用不在一個記憶體空間,不能直接呼叫,所以需要通過網路來表達呼叫的語義和傳達呼叫的資料。
RPC 並不是一個具體的技術,而是指整個網路遠端呼叫過程。
RPC 是一個泛化的概念,嚴格來說一切遠端過程呼叫手段都屬於 RP C範疇。各種開發語言都有自己的 RPC 框架。Java 中的 RPC 框架比較多,廣泛使用的有 RMI、Hessian、Dubbo
等。
原理
服務消費方(client)呼叫以本地呼叫方式呼叫服務。客戶端存根(client stub)接收到呼叫後負責將方法、引數等編碼成能在網路中傳輸的訊息體。然後,客戶端存根找到服務地址後,將訊息傳送給服務端。
服務提供方(server)收到序列化後的訊息,就按照解碼該訊息。然後,根據解碼結果呼叫本地服務,執行完畢後,將結果打包傳送給消費方。
服務消費方收到執行結果後,也是進行解碼後得到結果。
原理
使用場景
RPC 分散式服務,拆分應用進行服務化,提高開發效率,調優效能,節省競爭資源
_配置管理,_解決服務的地址資訊劇增,配置困難的問題
_服務依賴,_解決服務間依賴關係錯蹤複雜的問題
_服務擴容,_解決隨著訪問量的不斷增大,動態擴充套件服務提供方的機器的問題
核心功能
Remoting
:遠端通訊,提供對多種 NIO 框架抽象封裝,包括“同步轉非同步”和“請求-響應”模式的資訊交換方式。
Cluster
:服務框架,提供基於介面方法的透明遠端過程呼叫,包括多協議支援,以及軟負載均衡,失敗容錯,地址路由,動態配置等叢集支援。
Registry
:服務註冊中心,服務自動發現: 基於註冊中心目錄服務,使服務消費方能動態的查詢服務提供方,使地址透明,使服務提供方可以平滑增加或減少機器。
核心元件
_Provider:_服務的提供方
_Consumer:_呼叫遠端服務的服務消費方
_Registry:_服務註冊和發現的註冊中心
_Monitor:_統計服務呼叫次數和呼叫時間的監控中心
_Container:_服務執行容器
元件
服務註冊與發現
流程如下:
_1、_Provider(提供者)繫結指定埠並啟動服務
_2、_供者連線註冊中心,併發本機 IP、埠、應用資訊和提供服務資訊傳送至註冊中心儲存
_3、_Consumer(消費者),連線註冊中心 ,並傳送應用資訊、所求服務資訊至註冊中心
_4、_註冊中心根據消費者所求服務資訊匹配對應的提供者列表傳送至Consumer 應用快取。
_5、_Consumer 在發起遠端呼叫時基於快取的消費者列表擇其一發起呼叫。
_6、_Provider 狀態變更會實時通知註冊中心、在由註冊中心實時推送至Consumer設計的原因:
Consumer 與 Provider 解偶,雙方都可以橫向增減節點數。註冊中心對本身可做對等叢集,可動態增減節點,並且任意一臺宕掉後,將自動切換到另一臺
_7、_去中心化,雙方不直接依懶註冊中心,即使註冊中心全部當機短時間內也不會影響服務的呼叫
_8、_服務提供者無狀態,任意一臺宕掉後,不影響使用
流程
服務治理
治理原因
Dubbo的服務治理主要原因:
_1、_過多的服務 URL 配置困難。
_2、_負載均衡分配節點壓力過大的情況下也需要部署叢集。
_3、_服務依賴混亂,啟動順序不清晰。
_4、_過多服務導致效能指標分析難度較大,需要監控。
主要特性
_透明遠端呼叫:_就像呼叫本地方法一樣呼叫遠端方法;只需簡單配置,沒有任何 API 侵入
_負載均衡機制:_Client 端 LB,可在內網替代 F5 等硬體負載均衡器
_容錯重試機制:_服務 Mock 資料,重試次數、超時機制等
_自動註冊發現:_註冊中心基於介面名查詢服務提 供者的 IP 地址,並且能夠平滑新增或刪除服務提供者
_效能日誌監控:_Monitor 統計服務的呼叫次調和呼叫時間的監控中心
_服務治理中心:_路由規則,動態配置,服務降級,訪問控制,權重調整,負載均衡,等手動配置
_自動治理中心:_無,比如:熔斷限流機制、自動權重調整等(因此可以搭配SpringCloud的熔斷機制等進行開發)
服務治理
架構設計
整體架構
先看下 Dubbo 的整體架構圖:
圖例說明:
整體架構
圖中左邊淡藍背景的為服務消費方使用的介面,右邊淡綠色背景的為服務提供方使用的介面,位於中軸線上的為雙方都用到的介面。
圖中從下至上分為十層,各層均為單向依賴,右邊的黑色箭頭代表層之間的依賴關係,每一層都可以剝離上層被複用,其中,Service
和 Config
層為 API,其它各層均為 SPI。
圖中綠色小塊的為擴充套件介面,藍色小塊為實現類,圖中只顯示用於關聯各層的實現類。
圖中藍色虛線為初始化過程,即啟動時組裝鏈,紅色實線為方法呼叫過程,即執行時調時鏈,紫色三角箭頭為繼承,可以把子類看作父類的同一個節點,線上的文字為呼叫的方法。
各層說明
_config 配置層:_對外配置介面,以 ServiceConfig, ReferenceConfig 為中心,可以直接初始化配置類,也可以通過 spring 解析配置生成配置類
_proxy 服務代理層:_服務介面透明代理,生成服務的客戶端 Stub 和伺服器端 Skeleton,以ServiceProxy 為中心,擴充套件介面為 ProxyFactory
_registry 註冊中心層:_封裝服務地址的註冊與發現,以服務 URL 為中心,擴充套件介面為RegistryFactory, Registry, RegistryService
_cluster 路由層:_封裝多個提供者的路由及負載均衡,並橋接註冊中心,以 Invoker 為中心,擴充套件介面為 Cluster, Directory, Router, LoadBalance
_monitor 監控層:_RPC 呼叫次數和呼叫時間監控,以 Statistics 為中心,擴充套件介面為MonitorFactory, Monitor, MonitorService
_protocol 遠端呼叫層:_封裝 RPC 呼叫,以 Invocation, Result 為中心,擴充套件介面為 Protocol, Invoker, Exporter
_exchange 資訊交換層:_封裝請求響應模式,同步轉非同步,以 Request, Response 為中心,擴充套件介面為 Exchanger, ExchangeChannel, ExchangeClient, ExchangeServer
_transport 網路傳輸層:_抽象 mina 和 netty 為統一介面,以 Message 為中心,擴充套件介面為 Channel, Transporter, Client, Server, Codec
_serialize 資料序列化層:_可複用的一些工具,擴充套件介面為 Serialization, ObjectInput, ObjectOutput, ThreadPool
主要模組
dubbo-common
公共邏輯模組,包括 Util
類和通用模型。
dubbo-remoting
遠端通訊模組,相當於 Dubbo 協議的實現,如果 RPC 用 RMI 協議則不需要使用此包。
dubbo-rpc
遠端呼叫模組,抽象各種協議,以及動態代理,只包含一對一的呼叫,不關心叢集的管理。
dubbo-cluster
叢集模組,將多個服務提供方偽裝為一個提供方,包括:負載均衡、容錯、路由等,叢集的地址列表可以是靜態配置的,也可以是由註冊中心下發。
dubbo-registry
註冊中心模組,基於註冊中心下發地址的叢集方式,以及對各種註冊中心的抽象。
dubbo-monitor
監控模組,統計服務呼叫次數,呼叫時間的,呼叫鏈跟蹤的服務。
dubbo-config
配置模組,是 Dubbo 對外的 API ,使用者通過 Config 使用 Dubbo ,隱藏 Dubbo 所有細節。
dubbo-container
容器模組,是一個 Standalone
的容器,以簡單的 Main 載入 Spring 啟動,因為服務通常不需要 Tomcat/JBoss 等 Web 容器的特性,沒必要用 Web 容器去載入服務。
主要模組
呼叫方式
非同步呼叫
基於 NIO 的非阻塞實現並行呼叫,客戶端不需要啟動多執行緒即可完成並行呼叫多個遠端服務,相對多執行緒開銷較小
非同步呼叫
本地呼叫
使用了Injvm協議,是一個偽協議,它不開啟埠,不發起遠端呼叫,只在JVM內直接關聯,但執行Dubbo的Filter鏈。
Define injvm protocol:
<dubbo:protocol name="injvm" />
Set default protocol:
`<dubbo:provider protocol="injvm" />`
Set service protocol:
<dubbo:service protocol="injvm" />
Use injvm first:(服務暴露與服務引用都需要宣告injvm=“true”)
`<dubbo:consumer injvm="true" .../>`
`<dubbo:provider injvm="true" .../>`
`或`
`<dubbo:reference injvm="true" .../> <dubbo:service injvm="true" .../>`
容錯機制
呼叫流程
_1、_Cluster 將 Directory 中的多個 Invoker 偽裝成一個Invoker,對上層透明,偽裝過程包含了容錯邏輯
_2、_Router 負責從多個 Invoker 中按路由規則選出子集,比如讀寫分離,應用隔離等
_3、_LoadBalance 負責從多個 Invoker 中選出具體的一個用於本次呼叫,選的過程包含了負載均衡演算法
呼叫流程
容錯策略
Dubbo 官網提出總共有六種容錯策略
_1、_Failover Cluster
失敗自動切換,當出現失敗,重試其它伺服器。(預設)
_2、_Failfast Cluster
快速失敗,只發起一次呼叫,失敗立即報錯。通常用於非冪等性的寫操作,比如新增記錄。
_3、_Failsafe Cluster
失敗安全,出現異常時,直接忽略。通常用於寫入審計日誌等操作。
_4、_Failback Cluster
失敗自動恢復,後臺記錄失敗請求,定時重發。通常用於訊息通知操作。
_5、_Forking Cluster
並行呼叫多個伺服器,只要一個成功即返回。通常用於實時性要求較高的讀操作,但需要浪費更多服務資源。
可通過 forks=”2”來設定最大並行數。
_6、_Broadcast Cluster
廣播呼叫所有提供者,逐個呼叫,任意一臺報錯則報錯。(2.1.0 開始支援) 通常用於通知所有提供者更新快取或日誌等本地資源資訊。
總結:在實際應用中查詢語句容錯策略建議使用預設 Failover Cluster
,而增刪改建議使用 Failfast Cluster
或者使用 Failover Cluster
(retries=”0”)策略,防止出現資料重複新增等等其它問題!建議在設計介面時候把查詢介面方法單獨做一個介面提供查詢。
連線方式
Dubbo 的客戶端和服務端有三種連線方式,分別是:廣播、直連和使用Zookeeper
註冊中心。
Dubbo 廣播
這種方式是dubbo官方入門程式所使用的連線方式,但是這種方式有很多問題,在企業開發中不使用廣播的方式。
服務端配置:
`<!--配製dubbo-->`
`<!--提供應用資訊,用於計算依賴關係-->`
`<dubbo:application name="demo-service"/>`
`<!--使用multicast廣播註冊暴露服務地址-->`
`<dubbo:registry address="multicast://192.168.9.4:88888" />`
`<!--使用dubbo協議在20880埠暴露服務-->`
`<dubbo:protocol name="dubbo" port="20880"/>`
`<!--宣告暴露的服務介面-->`
`<dubbo:service interface="com.demo.manger.service.TestService" ref="testServiceImpl" />`
客戶端配置:
`<!--配合dubbo-->`
`<!--提供應用資訊,用於計算依賴關係-->`
`<dubbo:application name="demo-web"/>`
`<!--使用multicast廣播註冊中心暴露服務地址 -->`
`<dubbo:registry address="multicast://19.188.8.9:8888"/>`
`<!--宣告需要暴露的介面-->`
`<dubbo:reference interface="com.demo.manager.service.TestService" id="testService" timeout="1000000" />`
Dubbo 直連
這種方式在企業中一般在開發中環境中使用,但是生產環境很少使用,因為服務是直接呼叫,沒有使用註冊中心,很難對服務進行管理。Dubbo 直連,首先要取消廣播,然後客戶端直接到指定需要的服務的 url 獲取服務即可。
服務端配置:
`<!--配製dubbo-->`
`<!--提供應用資訊,用於計算依賴關係-->`
`<dubbo:application name="demo-service"/>`
`<!--使用multicast廣播註冊暴露服務地址-->`
`<-- <dubbo:registry address="multicast://192.168.9.4:88888" /> -->`
`<dubbo:registry adress="N/A">`
`<!--使用dubbo協議在20880埠暴露服務-->`
`<dubbo:protocol name="dubbo" port="20880"/>`
`<!--宣告暴露的服務介面-->`
`<dubbo:service interface="com.demo.manger.service.TestService" ref="testServiceImpl" />`
客戶端配置:
`<!--配合dubbo-->`
`<!--提供應用資訊,用於計算依賴關係-->`
`<dubbo:application name="demo-web"/>`
`<!--使用multicast廣播註冊中心暴露服務地址 -->`
`<-- <dubbo:registry address="multicast://19.188.8.9:8888"/> -->`
`<!--宣告需要暴露的介面-->`
`<dubbo:reference interface="com.demo.manager.service.TestService" id="testService" timeout="1000000" url="dubbo://127.0.0.1:20880" />`
zookeeper 註冊中心
Dubbo 註冊中心和廣播註冊中心配置類似,不過需要指定註冊中心型別和註冊中心地址,這個時候就不是把服務資訊進行廣播了,而是告訴給註冊中心進行管理,這個時候我們就需要有一個註冊中心,官方推薦使用 zookeeper 作為註冊中心。
Zookeeper 註冊中心
註冊中心負責服務地址的註冊與查詢,相當於目錄服務,服務提供者在啟動時與註冊中心互動,消費者不斷的發起請求獲取服務資訊,註冊中心不轉發請求,壓力較小
服務端配置:
`<!--配製dubbo-->`
`<!--提供應用資訊,用於計算依賴關係-->`
`<dubbo:application name="demo-service"/>`
`<!--使用multicast廣播註冊暴露服務地址-->`
`<!-- <dubbo:registry address="multicast://192.168.9.4:88888" /> -->`
`<!--<dubbo:registry adress="N/A"> -->`
`<dubbo:registry protocol="zookeeper" address="192.168.37,136:2181">`
`<!--使用dubbo協議在20880埠暴露服務-->`
`<dubbo:protocol name="dubbo" port="20880"/>`
`<!--宣告暴露的服務介面-->`
`<dubbo:service interface="com.demo.manger.service.TestService" ref="testServiceImpl" />`
客戶端配置:
`<!--配合dubbo-->`
`<!--提供應用資訊,用於計算依賴關係-->`
`<dubbo:application name="demo-web"/>`
`<!--使用multicast廣播註冊中心暴露服務地址 -->`
`<-- <dubbo:registry address="multicast://19.188.8.9:8888"/> -->`
`<dubbo:registry protocol="zookeeper" address="192.168.37.1336:2181"/>`
`<!--宣告需要暴露的介面-->`
`<dubbo:reference interface="com.demo.manager.service.TestService" id="testService" timeout="1000000" />`
策略
負載均衡策略
_1、_Random LoadBalance,隨機(預設的負載均衡策略)
RandomLoadBalance 是加權隨機演算法的具體實現,可以完全隨機,也可以按權重設定隨機概率。
_2、_RoundRobin LoadBalance,輪循
可以輪詢和加權輪詢。存在響應慢的提供者會累積請求的問題,比如:第二臺機器很慢,但沒掛,當請求調到第二臺時就卡在那,久而久之,所有請求都卡在調到第二臺上。
_3、_LeastActive LoadBalance,最少活躍呼叫數
活躍呼叫數越小,表明該服務提供者效率越高,單位時間內可處理更多的請求。此時應優先將請求分配給該服務提供者。
_4、_ConsistentHash LoadBalance,一致性 Hash
一致性 Hash 演算法,相同引數的請求一定分發到一個 provider 上去。provider 掛掉的時候,會基於虛擬節點均勻分配剩餘的流量,抖動不會太大。
叢集容錯策略
_1、_failover cluster(預設)
失敗自動切換,呼叫失敗時,自動重試其他機器。通常用於讀操作,但重試會帶來更長延遲。
_2、_Failfast Cluster
快速失敗,只發起一次呼叫,失敗立即報錯。通常用於非冪等性的寫操作,比如新增記錄。
_3、_Failsafe Cluster
失敗安全,出現異常時,直接忽略。通常用於寫入審計日誌等操作。
_4、_Failback Cluster
失敗自動恢復,後臺記錄失敗請求,定時重發。通常用於訊息通知操作。
_5、_Forking Cluster
並行呼叫多個伺服器,只要一個成功即返回。通常用於實時性要求較高的讀操作,但需要浪費更多服務資源。
動態代理策略
預設使用 javassist
動態位元組碼生成,建立代理類。也可以通過 spi 擴充套件機制配置自己的動態代理策略。
叢集容錯方案
- 配置說明,方案配置方式,優先使用消費端配置
`<!--服務端配置-->`
`<dubbo:service cluster="failover"/>`
`<!--消費端配置-->`
`<dubbo:reference cluster="failover"/>`
-
儘量在只在服務端進行配置
-
cluster型別均為小寫
-
預設為FailoverCluster失敗切換方案
叢集容錯方案support
FailoverCluster(預設):失敗切換
-
場景:呼叫失敗後切換其他服務
-
配置:
`<!--`
`retries:重試次數,不包括第一次,預設2次`
`-->`
`<dubbo:service cluster="failover" retries="3"/>`
-
程式碼實現邏輯:
1. 根據負載均衡策略選出需要呼叫的服務例項,排除已呼叫的
2. 執行選出的例項,並將其儲存到已呼叫列表中
3. 執行例項成功即返回
4. 執行例項不成功,為到最大重試次數則執行第一步,否則丟擲RpcException異常
FailbackCluster:失敗重試
-
場景:呼叫失敗時記錄失敗請求,定時重發
-
配置:
`<!--`
`retries:重試次數,不包括第一次,預設3次`
`failbacktasks:定時器中最大掛起任務數,預設100`
`-->`
`<dubbo:service cluster="failback" retries="5" failbacktasks="200"/>`
-
程式碼實現邏輯
1. 根據負載均衡策略選出需要呼叫的服務例項
2. 執行選出的例項
3. 執行例項成功即返回
4. 執行異常則建立延時5秒的定時任務,並加入時間輪定時器,第一次需要進行定時器初始化,分為32個時間片,每1秒滾動一次,最大掛起任務預設100個,超出最大任務數時丟擲RejectedExecutionException異常。
5. 重試執行定時任務,次數超出最大執行次數停止,並輸出error日誌,預設為3次。
FailfastCluster:快速失敗
-
場景:呼叫失敗立即報錯
-
配置:
`<dubbo:service cluster="failfast"/>`
-
程式碼實現邏輯
1. 根據負載均衡策略選出需要呼叫的服務例項
2. 執行選出的例項
3. 執行例項成功即返回,失敗丟擲RpcException異常
FailsafeCluster:安全失敗
-
場景:呼叫失敗後忽略
-
配置:
`<dubbo:service cluster="failsafe"/>`
-
程式碼實現邏輯
1. 根據負載均衡策略選出需要呼叫的服務例項
2. 執行選出的例項
3. 執行例項成功即返回,失敗輸出error日誌,並返RpcResult,視為忽略。
ForkingCluster:併發處理
-
場景:併發呼叫指定數量的服務,一個成功則返回,對實時性要求高的場景,要求快速返回,需要使用更多伺服器資源。
-
配置:
`<!--`
`forks:最大併發數,預設2`
`timeout:併發返回超時時間,預設1000ms`
`-->`
`<dubbo:service cluster="forking" forks="3" timeout="500"/>`
-
程式碼實現邏輯
1. 根據負載均衡策略選出幾個不同的服務例項
2. 併發執行選出的幾個例項,並將返回結果放入堵塞佇列中
3. 返回堵塞佇列中的第一個值,如規定時間內未獲取到佇列中的值或獲取到異常值則返回RPC異常。
BroadcastCluster:廣播
-
場景:廣播方式逐個呼叫服務提供者,有一個報錯則返回錯誤,多用於通知服務提供者更新本地資源資訊,如快取,日誌等。
-
配置:
`<dubbo:service cluster="broadcast"/>`
-
程式碼實現邏輯
1. 迴圈逐個執行所有服務例項資訊
2. 儲存一份返回結果和異常資訊
3. 執行完全部例項後,如異常資訊不為空,則丟擲異常資訊,否則返回最後一個例項的結果。
AvailableCluster:可用服務
-
場景:呼叫第一個可用服務
-
配置:
`<dubbo:service cluster="available"/>`
-
程式碼實現邏輯
1. 迴圈所有服務例項資訊
2. 執行第一個可用的例項,並返回結果
3. 如無可用例項則返回RpcException異常
MergeableCluster:合併處理
-
場景:返回合併或疊加處理結果
-
配置:
`<!--`
`merger:合併發放名`
`timeout:呼叫服務超時時間,預設1000ms`
`-->`
`<dubbo:service cluster="mergeable" merger="true" timeout="500"/>`
-
程式碼實現邏輯
1. 判斷merger,為空、null、0、false、N/A是執行第一個可用服務並返回結果,無可用則執行第一個例項,並返回結果。
2. 獲取方法例項的返回型別
3. 非同步呼叫所有例項,並將非同步結果Result儲存到結果集中,返回異常輸出error日誌
4. 結果集為空返回 RpcException,大小為 1時返回第一個Result
5. 當merger的第一個字元為“.”時,判斷當 merger 例項返回型別不為void,且返回型別必須是結果集中第一個返回型別的父型別或相同型別時,迴圈執行merger例項,每一次都傳入上一次的返回結果,最終返回獲取最後一次結果,非上述情況時迴圈執行merger例項,返回結果集中的第一個結果。
6. 當merger為true或default時使用Dubbo預設合併器,否則使用自定義merger合併器,合併後返回
RegistryAwareCluster:預設標識、註冊標識
-
場景:呼叫註冊預設標識的服務
-
配置:
`<!--`
`default:預設標識`
`-->`
`<dubbo:registry address="zookeeper://xxx..." default="true"/>`
`<dubbo:service cluster="registryaware"/>`
-
程式碼實現邏輯
1.8 迴圈所有服務例項資訊
2. 執行第一個可用的例項且default為true的例項
3. 無預設例項則執行第一個可用的例項
4. 無可用的例項則丟擲RpcException異常
主要配置
配置應用資訊:
`<dubbo:application name=“appName-provider” />`
配置註冊中心相關資訊:
`<dubbo:registryid=“zk” protocol=“zookeeper” address=“127.0.0.1:2181” />`
配置服務協議:
`<dubbo:protocol name=“dubbo” port=“20880” threadpool=“cached” threads=“80” />`
配置所有暴露服務預設值:
`<dubbo:provider registry=“zk” protocol=“dubbo” retries=“0” version=“1.0.0” timeout=“3000” threadpool=“cached” threads=“4”/>`
配置暴露服務:
`<dubbo:service interface=“com.orgname.app.serviceX” ref=“serviceX” />`
配置所有引用服務預設值:
`<dubbo:consumer check=“false” timeout=“1000” version=“1.0” retries=“0” async=“false” />`
註解配置:
`com.alibaba.dubbo.config.annotation.Service 配置暴露服務`
`com.alibaba.dubbo.config.annotation.Reference配置引用服務`
超時設定
Dubbo消費端
全域性超時配置
`<dubbo:consumer timeout="5000" />`
指定介面以及特定方法超時配置
`<dubbo:reference interface="com.foo.BarService" timeout="2000">`
`<dubbo:method name="sayHello" timeout="3000" />`
`</dubbo:reference>`
Dubbo服務端
全域性超時配置
`<dubbo:provider timeout="5000" />`
指定介面以及特定方法超時配置
`<dubbo:provider interface="com.foo.BarService" timeout="2000">`
`<dubbo:method name="sayHello" timeout="3000" />`
`</dubbo:provider>`
支援協議
_1、_Dubbo 協議(官方推薦協議)
優點:採用NIO複用單一長連線,並使用執行緒池併發處理請求,減少握手和加大併發效率,效能較好(推薦使用)
缺點:大檔案上傳時,可能出現問題(不使用 Dubbo 檔案上傳)
_2、_RMI(Remote Method Invocation)協議
優點:JDK 自帶的能力。可與原生 RMI 互操作,基於 TCP 協議
缺點:偶爾連線失敗.
_3、_Hessian協議
優點:可與原生 Hessian 互操作,基於 HTTP 協議
缺點:需 hessian.jar 支援,http 短連線的*_開銷大_8
常用設計模式
Dubbo 框架在初始化和通訊過程中使用了多種設計模式,可靈活控制類載入、許可權控制等功能。
工廠模式
Provider 在 export 服務時,會呼叫 ServiceConfig 的 export 方法。ServiceConfig 中有個欄位:
`private static final Protocol protocol =`
`ExtensionLoader.getExtensionLoader(Protocol.class).getAdaptiveExtension();`
Dubbo 裡有很多這種程式碼。這也是一種工廠模式,只是實現類的獲取採用了 JDK SPI 的機制。這麼實現的優點是可擴充套件性強,想要擴充套件實現,只需要在 classpath下增加個檔案就可以了,程式碼零侵入。另外,像上面的 Adaptive 實現,可以做到呼叫時動態決定呼叫哪個實現,但是由於這種實現採用了動態代理,會造成程式碼除錯比較麻煩,需要分析出實際呼叫的實現類。
裝飾器模式
Dubbo 在啟動和呼叫階段都大量使用了裝飾器模式。以 Provider 提供的呼叫鏈為例,具體的呼叫鏈程式碼是在 ProtocolFilterWrapper 的buildInvokerChain 完成的,具體是將註解中含有 group=provider 的 Filter 實現,按照 order 排序,最後的呼叫順序是:
`EchoFilter -> ClassLoaderFilter -> GenericFilter -> ContextFilter ->`
`ExecuteLimitFilter -> TraceFilter -> TimeoutFilter -> MonitorFilter ->`
`ExceptionFilter`
更確切地說,這裡是裝飾器和責任鏈模式的混合使用。例如,EchoFilter 的作用是判斷是否是回聲測試請求,是的話直接返回內容,這是一種責任鏈的體現。而像ClassLoaderFilter 則只是在主功能上新增了功能,更改當前執行緒的 ClassLoader,這是典型的裝飾器模式。
觀察者模式
Dubbo 的 Provider 啟動時,需要與註冊中心互動,先註冊自己的服務,再訂閱自己的服務,訂閱時,採用了觀察者模式,開啟一個 listener。註冊中心會每 5 秒定時檢查是否有服務更新,如果有更新,向該服務的提供者傳送一個 notify 訊息,provider 接受到 notify 訊息後,即執行 NotifyListener 的 notify 方法,執行監聽器方法。
動態代理模式
Dubbo 擴充套件 JDK SPI 的類 ExtensionLoader 的 Adaptive 實現是典型的動態代理實現。Dubbo 需要靈活地控制實現類,即在呼叫階段動態地根據引數決定呼叫哪個實現類,所以採用先生成代理類的方法,能夠做到靈活的呼叫。生成代理類的程式碼是 ExtensionLoader 的 createAdaptiveExtensionClassCode 方法。代理類的主要邏輯是,獲取 URL 引數中指定引數的值作為獲取實現類的 key
工作流程
整體流程:
第一步:provider 向註冊中心去註冊
第二步:consumer 從註冊中心訂閱服務,註冊中心會通知 consumer 註冊好的服務
第三步:consumer 呼叫 provider
第四步:consumer 和 provider 都非同步通知監控中心
流程圖
總結
最後用一張圖來形象的模擬 Dubbo 的使用:
使用
以上只是我總結的一些關於 dubbo 最基礎的原理及使用介紹,至於程式碼編寫過程的 bug 處理經驗,環境搭建、專案佈局等等問題,需要我們在平時開發中,將系統知識與實戰經驗相結合去總結,這樣才能真正的去掌握這項技術點。
Dubbo 目前是我用到過的最多的分散式框架,寫出來的內容也是最多的,不過由於Dubbo用的太多,而 SpringCloud 難度比 Dubbo 要小很多,現在大部分專案都即將開始轉投到了 SpringCloud 上面,後面也會出更多的 SpringCloud 相關的文章。