1. 程式人生 > >你應該知道的 RPC 原理(好文,忍不住轉到自己空間。)

你應該知道的 RPC 原理(好文,忍不住轉到自己空間。)

在校期間大家都寫過不少程式,比如寫個hello world服務類,然後本地呼叫下,如下所示。這些程式的特點是服務消費方和服務提供方是本地呼叫關係。

而一旦踏入公司尤其是大型網際網路公司就會發現,公司的系統都由成千上萬大大小小的服務組成,各服務部署在不同的機器上,由不同的團隊負責。這時就會遇到兩個問題:1)要搭建一個新服務,免不了需要依賴他人的服務,而現在他人的服務都在遠端,怎麼呼叫?2)其它團隊要使用我們的服務,我們的服務該怎麼釋出以便他人呼叫?下文我們將對這兩個問題展開探討。

Java
123publicinterfaceHelloWorldService
{StringsayHello(Stringmsg);}
Java
1 2 3 4 5 6 7 8 publicclassHelloWorldServiceImplimplementsHelloWorldService{ @Override publicStringsayHello(Stringmsg){ Stringresult="hello world "+msg; System.out.println(result); returnresult; } }
Java
123456publicclassTest{publicstaticvoidmain(String[]args){HelloWorldService helloWorldService=newHelloWorldServiceImpl();helloWorldService.sayHello("test");}}

1 如何呼叫他人的遠端服務?

由於各服務部署在不同機器,服務間的呼叫免不了網路通訊過程,服務消費方每呼叫一個服務都要寫一坨網路通訊相關的程式碼,不僅複雜而且極易出錯。

如果有一種方式能讓我們像呼叫本地服務一樣呼叫遠端服務,而讓呼叫者對網路通訊這些細節透明,那麼將大大提高生產力,比如服務消費方在執行helloWorldService.sayHello(“test”)時,實質上呼叫的是遠端的服務。這種方式其實就是RPC(Remote Procedure Call Protocol),在各大網際網路公司中被廣泛使用,如阿里巴巴的hsf、dubbo(開源)、Facebook的thrift(開源)、Google grpc(開源)、Twitter的finagle等。

要讓網路通訊細節對使用者透明,我們自然需要對通訊細節進行封裝,我們先看下一個RPC呼叫的流程:

  • 1)服務消費方(client)呼叫以本地呼叫方式呼叫服務;
  • 2)client stub接收到呼叫後負責將方法、引數等組裝成能夠進行網路傳輸的訊息體;
  • 3)client stub找到服務地址,並將訊息傳送到服務端;
  • 4)server stub收到訊息後進行解碼;
  • 5)server stub根據解碼結果呼叫本地的服務;
  • 6)本地服務執行並將結果返回給server stub;
  • 7)server stub將返回結果打包成訊息併發送至消費方;
  • 8)client stub接收到訊息,並進行解碼;
  • 9)服務消費方得到最終結果。

RPC的目標就是要2~8這些步驟都封裝起來,讓使用者對這些細節透明。

1.1 怎麼做到透明化遠端服務呼叫?

怎麼封裝通訊細節才能讓使用者像以本地呼叫方式呼叫遠端服務呢?對java來說就是使用代理!java代理有兩種方式:1) jdk 動態代理;2)位元組碼生成。儘管位元組碼生成方式實現的代理更為強大和高效,但程式碼不易維護,大部分公司實現RPC框架時還是選擇動態代理方式。

下面簡單介紹下動態代理怎麼實現我們的需求。我們需要實現RPCProxyClient代理類,代理類的invoke方法中封裝了與遠端服務通訊的細節,消費方首先從RPCProxyClient獲得服務提供方的介面,當執行helloWorldService.sayHello(“test”)方法時就會呼叫invoke方法。

Java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22