Dubbo使用及底層通信原理


 Dubbo采用的是一種非常簡單的模型,要么是提供方提供服務,要么是消費方消費服務,所以基於這一點可以抽象出服務提供方(Provider)和服務消費方(Consumer)兩個角色。dubbo除了可以提供服務之外,還可以實現軟負載均衡。它還提供了兩個功能Monitor 監控中心和調用中心。這兩個是可選的,需要單獨配置。

常用場景:

Dubbo采用單一長連接和NIO異步通訊,適合於小數據量大並發的服務調用,以及服務消費者機器數遠大於服務提供者機器數的情況

Dubbo原理

 

   

 

1. 節點角色說明

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

Consumer:調用遠程服務的服務消費方

Registry:服務注冊與發現的注冊中心(Provider將服務暴露給它,Consumer在這里查找所需服務)

Monitor:統計服務的調用次數和調用事件的監控中心

Cotainer:服務運行容器,常見的容器有Spring容器。

2. 原理

整個發布-訂閱的過程可以簡單的理解為生產者-消費者模型+注冊中心+監控中心:

  • 啟動容器,加載,運行服務提供者。
  • 服務提供者在啟動時,在注冊中心發布注冊自己提供的服務。
  • 服務消費者在啟動時,在注冊中心訂閱自己所需的服務。

如果考慮失敗或變更的情況,就需要考慮下面的過程。

  • 注冊中心返回服務提供者地址列表給消費者,如果有變更,注冊中心將基於長連接推送變更數據給消費者。
  • 服務消費者,從提供者地址列表中,基於軟負載均衡算法,選一台提供者進行調用,如果調用失敗,再選另一台調用。
  • 服務消費者和提供者,在內存中累計調用次數和調用時間,定時每分鍾發送一次統計數據到監控中心。

 

分析源代碼,基本原理如下:

  1. client一個線程調用遠程接口,生成一個唯一的ID(比如一段隨機字符串,UUID等),Dubbo是使用AtomicLong從0開始累計數字的
  2. 將打包的方法調用信息(如調用的接口名稱,方法名稱,參數值列表等),和處理結果的回調對象callback,全部封裝在一起,組成一個對象object
  3. 向專門存放調用信息的全局ConcurrentHashMap里面put(ID, object)
  4. 將ID和打包的方法調用信息封裝成一對象connRequest,使用IoSession.write(connRequest)異步發送出去
  5. 當前線程再使用callback的get()方法試圖獲取遠程返回的結果,在get()內部,則使用synchronized獲取回調對象callback的鎖, 再先檢測是否已經獲取到結果,如果沒有,然后調用callback的wait()方法,釋放callback上的鎖,讓當前線程處於等待狀態。
  6. 服務端接收到請求並處理后,將結果(此結果中包含了前面的ID,即回傳)發送給客戶端,客戶端socket連接上專門監聽消息的線程收到消息,分析結果,取到ID,再從前面的ConcurrentHashMap里面get(ID),從而找到callback,將方法調用結果設置到callback對象里。
  7. 監聽線程接着使用synchronized獲取回調對象callback的鎖(因為前面調用過wait(),那個線程已釋放callback的鎖了),再notifyAll(),喚醒前面處於等待狀態的線程繼續執行(callback的get()方法繼續執行就能拿到調用結果了),至此,整個過程結束。

思考

了解了前面的原理部分,思考幾個問題考察一下自己是否真的懂了.

1. 當前線程怎么讓它“暫停”,等結果回來后,再向后執行?

答:先生成一個對象obj,在一個全局map里put(ID,obj)存放起來,再用synchronized獲取obj鎖,再調用obj.wait()讓當前線程處於等待狀態,然后另一消息監聽線程等到服 務端結果來了后,再map.get(ID)找到obj,再用synchronized獲取obj鎖,再調用obj.notifyAll()喚醒前面處於等待狀態的線程。

【后面這句是廢話】回想之前做項目時,需在前台調用某一服務(該服務要求在后一服務前發生),當時還不懂dubbo,以為調用服務及其相應的行為都是同步的,沒有使用嵌套,結果導致代碼邏輯未達到預期設想。

 

2. Socket通信是一個全雙工的方式,如果有多個線程同時進行遠程方法調用,這時建立在client server之間的socket連接上會有很多雙方發送的消息傳遞,前后順序也可能是亂七八糟的,server處理完結果后,將結果消息發送給client,client收到很多消息,怎么知道哪個消息結果是原先哪個線程調用的?

答:使用一個ID,讓其唯一,然后傳遞給服務端,再服務端又回傳回來,這樣就知道結果是原先哪個線程的了。

 

 

 

 

參考文章列表:

https://blog.csdn.net/en_joker/article/details/89946034

https://segmentfault.com/a/1190000019896723

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM