dubbo學習思路梳理
dubbo 要解決的問題
rpc呼叫需要定製。額外的工作量
分散式服務中,服務動輒幾十上百,相互之間的呼叫錯綜複雜,相互依賴嚴重
對叢集性的服務,需要負載策略
對叢集性的服務,能動態擴充套件節點
dubbo 標籤
服務方和消費方都要配置
2 、服務方的標籤:
上層屬性,能夠自動被下層繼承
provider 標籤做預設配置使用,主要啟一個繼承作用。比如 timeout = 1s 。
protocol 指定協議, service 配置目標實現類
3 、消費方的標籤
3 、消費方繼承服務方屬性
只有服務提供方,知道 service 引數怎麼配置最合適。 timeout = 1s
dubbo配置 檔案
dubbo 配置的步驟
1、把服務交給ioc容器管理
2 、 dubbo 把容器內的三個 service ,開放成 rpc 服務
3 、消費方通過 dubbo ,得到 rpc 服務的代理物件
4 、消費方啟動 spring 容器,初始化了 dubbo
5 、 dubbo 的叢集容錯配置 ---- 呼叫失敗怎麼?哪些策略?
failover :重試其它 provider 的服務 --------- 冪等時才能使用(比如讀操作)
failfast :直接返回失敗 --------- 一般的寫操作,不能重試
failsafe :忽略錯誤 --------- 無關緊要的服務使用,如打日誌 / 發郵件
6 、負載配置 -----
random :隨機訪問每個 provider
roundrobin :輪詢訪問
leastactive :誰最輕鬆,訪問誰
7 、宣告式快取 ---- 將方法的引數與返回 value 快取
lru :最少使用原則刪除快取(此引數長期未調,就不快取了)
threadlocal :對呼叫者快取(下次還是你呼叫,就返回快取的資料)
rpc 呼叫過程
原始碼走讀
服務端在中轉物件上,設定 --- 介面 / 實現 /url
消費端建立代理物件,設定 介面 /url
呼叫過程
中轉物件,跟著代理物件動作,猴子學樣;
dubbo 代理物件與中轉物件(目標 ) 建立的關係,通過 URL 來傳遞的。
URL 是整個 dubbo 裡的總資訊描述符。
dubbo 一般選擇使用哪個協議?
最常用,就是 dubbo 協議 /hession 協議
選擇協議,一般就考量協議的效能,就數這兩個協議效率高
zookeeper 在 dubbo 裡,處於什麼位置
zk 在 dubbo 裡起的作用 --- 資料庫 + 訊息推送
同樣的,使用 redis 一樣能做資料的記錄和訊息投送,這對 dubbo 來說,沒有區別。
dubbo 初始化過程
1 、標籤入口 ---- DubboNamespaceHandler
2 、下面 每個配置標籤 ---- 對應一個 ReferenceBean 例項
2.1 、把 dubbo : referencce ( dubbo : service 同理 )標籤配置的屬性,全讀出來 ---- set 進入 ReferenceBean 物件,物件例項由 IOC 容器管理
2.2 、 ReferenceBean ( ServiceBean 同理 )實現了, initializingBean 介面,因此初始化完成時,會呼叫其 afterPropertiesSet 方法
2.3 、 afterPropertiesSet 方法內,進行 dubbo 服務配置(建立消費端的代理物件 / 服務端的中轉物件 / 向 zk 註冊資訊 / 訂閱資訊等)
這裡會對標籤中設定的每個協議,進行一行處理
2.4 、協議建立中轉物件和消費代理
2.5、dubbo的初始化結構圖:主線是ServiceBean 和 ReferenceBean的初始化
3 、 spi 機制概念
------------- 本質是解決同一個介面,有多種實現時,使用者如何能夠方便選擇實現的問題
3.1 、同一個介面,多個實現(類似設計模式 -- 策略模式)
3.2 、看 jdk 的 spi 如何配置使用的
jdk 中,選擇 SpiService 的實現,方法是在 jar 中放置一個 META-INF/services 目錄,目錄中存放一個文字檔案(檔名 ---- 是 SpiService 介面的全路徑名),文字中列入你選擇的實現類(一行放一個 ------ 是實現類的全路徑名)
有了上述配置,在 java 程式中,使用 ServiceLoader.load(SpiService.class) ,即可將配置中選擇的實現類,例項化並放入一個集合中,供我們使用,如下圖:
3.3 、 dubbo 的 spi ------ 比 jdk 的選擇方案,要牛叉一點
與 jdk 相比, dubbo 將選擇權下放到了配置檔案中(你配置誰,它使為你例項化誰)
dubbo 的目標,以上圖 cluster 為例, failsafe/failover/failfast 都是 cluster 的一種實現,現在我 們可以在標籤配置時,方便地進行選擇
5、dubbo的Spi實現原理---解讀其核心ExtensionLoader
5.1 、看原始碼疑雲:
疑問: dubbo 中 reference 使用的 protoc ·ol --- 是靜態類變數
而ReferenceConfig ( ReferenceBean 的父級) 是每個標籤一個例項物件(每個物件配置的 protocol 是不同的)
此時 protocol 的對應一定出問題
結論:上面步驟中,得到的 protocol 是個代理類,不是真實的協議實現
5.2、ExtensionLoader 的載入步驟
5.2.1、 getExtensionLoader (Protocol. class ) 為 protocol介面生成一個載入器
5.2.2、getAdaptiveExtension(), 使用載入器生成一個代理物件 ---- protocol介面物件
5.2.3 、代理物件執行時,根據引數(副檔名 extName )選擇實際物件 ------
5.2.4 、最後的效果:每個介面擴充套件點 ----- 對應一個 ExtensionLoader 載入器,如:
protocol -------------- ExtensionLoader 例項 < protocol>
filter -------------- ExtensionLoader 例項 < filter >
loadbalance -------------- ExtensionLoader 例項 < loadbalance >
5.2.5 、代理類的邏輯
代理類的建立,是通過動態程式碼,生成一個類原始碼,然後經過編譯得到代理類的 class ,如上圖
代理類生成原始碼的邏輯,只生介面中,標註了@Adaptive 的 方法,如下:
5.2.6 、 dubbo 的 spi 整體執行邏輯
a 、 dubbo 啟動載入實現類時,以 key- 例項 方式 map 快取各個實現類
b 、實際呼叫時,通過 key -- 取實現需要那個實現
c 、呼叫的發生,由生成的代理物件的來發起,最終是從 URL 匯流排中,找出 extName 值,
extName 做為別說,在快取 map 中取出正確的實現實現類