RPC的解釋以及RPC和Restful、RPC和RMI的區別

如何科學的解釋RPC

提及RPC,就不能不提到分佈式,這個促使RPC誕生的領域。html

假設你有一個計算器接口,Calculator,以及它的實現類CalculatorImpl,那麼在系統仍是單體應用時,你要調用Calculator的add方法來執行一個加運算,直接new一個CalculatorImpl,而後調用add方法就好了,這其實就是很是普通的本地函數調用,由於在同一個地址空間,或者說在同一塊內存,因此經過方法棧和參數棧就能夠實現。java

 
 

 

如今,基於高性能和高可靠等因素的考慮,你決定將系統改造爲分佈式應用,將不少能夠共享的功能都單獨拎出來,好比上面說到的計算器,你單獨把它放到一個服務裏頭,讓別的服務去調用它。apache

 
 

這下問題來了,服務A裏頭並無CalculatorImpl這個類,那它要怎樣調用服務B的CalculatorImpl的add方法呢?編程

有同窗會說,能夠模仿B/S架構的調用方式呀,在B服務暴露一個Restful接口,而後A服務經過調用這個Restful接口來間接調用CalculatorImpl的add方法。緩存

很好,這已經很接近RPC了,不過若是是這樣,那每次調用時,是否是都須要寫一串發起http請求的代碼呢?好比httpClient.sendRequest...之類的,能不能像本地調用同樣,去發起遠程調用,讓使用者感知不到遠程調用的過程呢,像這樣:網絡

@Reference private Calculator calculator; ... calculator.add(1,2); ... 

這時候,有同窗就會說,用代理模式呀!並且最好是結合Spring IoC一塊兒使用,經過Spring注入calculator對象,注入時,若是掃描到對象加了@Reference註解,那麼就給它生成一個代理對象,將這個代理對象放進容器中。而這個代理對象的內部,就是經過httpClient來實現RPC遠程過程調用的。架構

可能上面這段描述比較抽象,不過這就是不少RPC框架要解決的問題和解決的思路,好比阿里的Dubbo。負載均衡

總結一下,RPC要解決的兩個問題:框架

  1. 解決分佈式系統中,服務之間的調用問題。
  2. 遠程調用時,要可以像本地調用同樣方便,讓調用者感知不到遠程調用的邏輯。

如何實現一個RPC

實際狀況下,RPC不多用到http協議來進行數據傳輸,畢竟我只是想傳輸一下數據而已,何須動用到一個文本傳輸的應用層協議呢,我爲何不直接使用二進制傳輸?好比直接用Java的Socket協議進行傳輸?異步

無論你用何種協議進行數據傳輸,一個完整的RPC過程,均可以用下面這張圖來描述:

 
 

以左邊的Client端爲例,Application就是rpc的調用方,Client Stub就是咱們上面說到的代理對象,也就是那個看起來像是Calculator的實現類,其實內部是經過rpc方式來進行遠程調用的代理對象,至於Client Run-time Library,則是實現遠程調用的工具包,好比jdk的Socket,最後經過底層網絡實現實現數據的傳輸。

這個過程當中最重要的就是序列化和反序列化了,由於數據傳輸的數據包必須是二進制的,你直接丟一個Java對象過去,人家可不認識,你必須把Java對象序列化爲二進制格式,傳給Server端,Server端接收到以後,再反序列化爲Java對象。

下一次我也將經過代碼,給你們演示一下,如何實現一個簡單的RPC。

RPC vs Restful

其實這二者並非一個維度的概念,總得來講RPC涉及的維度更廣。

若是硬要比較,那麼能夠從RPC風格的url和Restful風格的url上進行比較。

好比你提供一個查詢訂單的接口,用RPC風格,你可能會這樣寫:

/queryOrder?orderId=123

用Restful風格呢?

Get  
/order?orderId=123

RPC是面向過程,Restful是面向資源,而且使用了Http動詞。從這個維度上看,Restful風格的url在表述的精簡性、可讀性上都要更好。

RPC vs RMI

嚴格來講這二者也不是一個維度的。

RMI是Java提供的一種訪問遠程對象的協議,是已經實現好了的,能夠直接用了。

而RPC呢?人家只是一種編程模型,並無規定你具體要怎樣實現,你甚至均可以在你的RPC框架裏面使用RMI來實現數據的傳輸,好比Dubbo:Dubbo - rmi協議

RPC沒那麼簡單

要實現一個RPC不算難,難的是實現一個高性能高可靠的RPC框架。

好比,既然是分佈式了,那麼一個服務可能有多個實例,你在調用時,要如何獲取這些實例的地址呢?

這時候就須要一個服務註冊中心,好比在Dubbo裏頭,就可使用Zookeeper做爲註冊中心,在調用時,從Zookeeper獲取服務的實例列表,再從中選擇一個進行調用。

那麼選哪一個調用好呢?這時候就須要負載均衡了,因而你又得考慮如何實現複雜均衡,好比Dubbo就提供了好幾種負載均衡策略。

這還沒完,總不能每次調用時都去註冊中心查詢實例列表吧,這樣效率多低呀,因而又有了緩存,有了緩存,就要考慮緩存的更新問題,blablabla......

你覺得就這樣結束了,沒呢,還有這些:

  • 客戶端總不能每次調用完都乾等着服務端返回數據吧,因而就要支持異步調用;
  • 服務端的接口修改了,老的接口還有人在用,怎麼辦?總不能讓他們都改了吧?這就須要版本控制了;
  • 服務端總不能每次接到請求都立刻啓動一個線程去處理吧?因而就須要線程池;
  • 服務端關閉時,還沒處理完的請求怎麼辦?是直接結束呢,仍是等所有請求處理完再關閉呢?
  • ......

如此種種,都是一個優秀的RPC框架須要考慮的問題。

固然,接下來咱們仍是先實現一個簡單的RPC,再在上面一步步優化!

做者:柳樹之
連接:https://www.jianshu.com/p/2accc2840a1b來源:簡書著做權歸做者全部。商業轉載請聯繫做者得到受權,非商業轉載請註明出處。

相關文章
相關標籤/搜索