什麼是rpc架構?
先回答第一個問題:什麼是RPC架構? 如果用一句話概括RPC就是:遠端調用架構(Remote Procedure Call)
![](https://img.laitimes.com/img/__Qf2AjLwojIjJCLyojI0JCLicmbw5SMwUDMjNTNklzYjR2NjdDOwMGZ0gTNyUjZlBTMwcDOi9CX5d2bs92Yl1iclB3bsVmdlR2LcNWaw9CXt92Yu4GZjlGbh5yYjV3Lc9CX6MHc0RHaiojIsJye.png)
那什麼是遠端調用?
通常我們調用一個php中的方法,比如這樣一個函數方法: localAdd(10, 20),localAdd方法的具體實作要麼是使用者自己定義的,要麼是php庫函數中自帶的,也就說在localAdd方法的代碼實作在本地,它是一個本地調用!
遠端調用意思就是:被調用方法的具體實作不在程式運作本地,而是在别的某個遠端地方。
最早在 Nelson 的論文中指出實作 RPC 的程式包括 5 個理論模型部分:
User
User-stub
RPCRuntime
Server-stub
Server
這 5 個部分的關系如下圖所示:
這裡 User 就是 Client 端。當 User 想發起一個遠端調用時,它實際是通過本地調用 User-stub。 User-stub 負責将調用的接口、方法和參數通過約定的協定規範進行編碼并通過本地的 RPCRuntime 執行個體傳輸到遠端的執行個體。 遠端 RPCRuntime 執行個體收到請求後交給 Server-stub 進行解碼後發起向本地端 Server 的調用,調用結果再傳回給 User 端。
遠端調用原理
比如 A (client) 調用 B (server) 提供的remoteAdd方法:
首先A與B之間建立一個TCP連接配接;
然後A把需要調用的方法名(這裡是remoteAdd)以及方法參數(10, 20)序列化成位元組流發送出去;
B接受A發送過來的位元組流,然後反序列化得到目标方法名,方法參數,接着執行相應的方法調用(可能是localAdd)并把結果30傳回;A接受遠端調用結果,輸出30。
RPC架構就是把我剛才說的這幾點些細節給封裝起來,給使用者暴露簡單友好的API使用。
遠端調用的好處
解耦:當server需要對方法内實作修改時,client完全感覺不到,不用做任何變更;這種方式在跨部門,跨公司合作的時候經常用到,并且方法的提供者我們通常稱為:服務的暴露。
RPC與Socket有什麼差別?
通過上面的簡單闡述,好像RPC與Socket 好像啊。都是調用遠端的方法,都是client/server模式,我之前也寫了一篇文章: 細說socket 那他們有啥差別呢?
RPC(遠端過程調用)采用客戶機/伺服器模式實作兩個程序之間互相通信。socket是RPC經常采用的通信手段之一,RPC是在Socket的基礎上實作的,它比socket需要更多的網絡和系統資源。除了Socket,RPC還有其他的通信方法,比如:http、作業系統自帶的管道等技術來實作對于遠端程式的調用。微軟的Windows系統中,RPC就是采用命名管道進行通信。
RPC與REST有什麼差別?
通過了解RPC後,我們知道是RPC是client/server模式的,調用遠端的方法,REST也是我們熟悉的一套API調用協定方法,它也是基于client/server模式的,調用遠端的方法的,那他倆又有啥差別呢?
REST API 和 RPC 都是在 Server端 把一個個函數封裝成接口暴露出去,以供 Client端 調用,不過 REST API 是基于 HTTP協定的,REST緻力于通過http協定中的POST/GET/PUT/DELETE等方法和一個可讀性強的URL來提供一個http請求。而 RPC 則可以不基于 HTTP協定
是以,如果是後端兩種語言互相調用,用 RPC 可以獲得更好的性能(省去了 HTTP 報頭等一系列東西),應該也更容易配置。如果是前端通過 AJAX 調用後端,那麼用 REST API 的形式比較好(因為無論如何也避不開 HTTP 這道坎)。
本地過程調用
RPC就是要像調用本地的函數一樣去調遠端函數。在研究RPC前,我們先看看本地調用是怎麼調的。假設我們要調用函數Multiply來計算lvalue * rvalue的結果:
int Multiply(int l, int r) {
int y = l * r;
return y;
}
int lvalue = 10;
int rvalue = 20;
int l_times_r = Multiply(lvalue, rvalue);
那麼在第8行時,我們實際上執行了以下操作:
将 lvalue 和 rvalue 的值壓棧
進入Multiply函數,取出棧中的值10 和 20,将其賦予 l 和 r
執行第2行代碼,計算 l * r ,并将結果存在 y
将 y 的值壓棧,然後從Multiply傳回
第8行,從棧中取出傳回值 200 ,并指派給 l_times_r
以上5步就是執行本地調用的過程。
遠端過程調用帶來的新問題
在遠端調用時,我們需要執行的函數體是在遠端的機器上的,也就是說,Multiply是在另一個程序中執行的。這就帶來了幾個新問題:
Call ID映射。我們怎麼告訴遠端機器我們要調用Multiply,而不是Add或者FooBar呢?在本地調用中,函數體是直接通過函數指針來指定的,我們調用Multiply,編譯器就自動幫我們調用它相應的函數指針。但是在遠端調用中,函數指針是不行的,因為兩個程序的位址空間是完全不一樣的。是以,在RPC中,所有的函數都必須有自己的一個ID。這個ID在所有程序中都是唯一确定的。用戶端在做遠端過程調用時,必須附上這個ID。然後我們還需要在用戶端和服務端分别維護一個 {函數 <--> Call ID} 的對應表。兩者的表不一定需要完全相同,但相同的函數對應的Call ID必須相同。當用戶端需要進行遠端調用時,它就查一下這個表,找出相應的Call ID,然後把它傳給服務端,服務端也通過查表,來确定用戶端需要調用的函數,然後執行相應函數的代碼。
序列化和反序列化。用戶端怎麼把參數值傳給遠端的函數呢?在本地調用中,我們隻需要把參數壓到棧裡,然後讓函數自己去棧裡讀就行。但是在遠端過程調用時,用戶端跟服務端是不同的程序,不能通過記憶體來傳遞參數。甚至有時候用戶端和服務端使用的都不是同一種語言(比如服務端用C++,用戶端用Java或者Python)。這時候就需要用戶端把參數先轉成一個位元組流,傳給服務端後,再把位元組流轉成自己能讀取的格式。這個過程叫序列化和反序列化。同理,從服務端傳回的值也需要序列化反序列化的過程。
網絡傳輸。遠端調用往往用在網絡上,用戶端和服務端是通過網絡連接配接的。所有的資料都需要通過網絡傳輸,是以就需要有一個網絡傳輸層。網絡傳輸層需要把Call ID和序列化後的參數位元組流傳給服務端,然後再把序列化後的調用結果傳回用戶端。隻要能完成這兩者的,都可以作為傳輸層使用。是以,它所使用的協定其實是不限的,能完成傳輸就行。盡管大部分RPC架構都使用TCP協定,但其實UDP也可以,而gRPC幹脆就用了HTTP2。Java的Netty也屬于這層的東西。
是以,要實作一個RPC架構,其實隻需要把以上三點實作了就基本完成了。
Call ID映射可以直接使用函數字元串,也可以使用整數ID。映射表一般就是一個哈希表。
序列化反序列化可以自己寫,也可以使用Protobuf或者FlatBuffers之類的。
網絡傳輸庫可以自己寫socket,或者用asio,ZeroMQ,Netty之類。
大廠流行的rpc架構有哪些?
1、Google之gprc
https://github.com/grpc/grpc https://github.com/google/protobuf http://doc.oschina.net/grpc2、Facebook之thrift
Thrift 源于Facebook,在 2007 年 Facebook 将 Thrift 作為一個開源項目送出給了 Apache 基金會。
http://thrift.apache.org/ http://thrift.apache.org/lib/ http://thrift.apache.org/lib/cpp https://github.com/apache/thrift3、Tencent之Tars
騰訊微服務架構Tars介紹
https://github.com/TarsCloud/Tars https://github.com/TarsCloud/TarsCpp https://github.com/TarsCloud/TarsGo https://github.com/Tencent/phxrpc,前身是Svrkit
https://github.com/loveyacper/ananas熱心前騰訊大咖DIY,C++實作
4、Baidu之brpc
brpc又稱為baidu-rpc,是百度開發一款“遠端過程調用”網絡架構。C++實作。
https://github.com/brpc/brpc5、golang之rpcx
rpcx是一個類似阿裡巴巴 Dubbo 和微網誌 Motan 的分布式的RPC服務架構,基于Golang net/rpc實作。号稱是最好的Go語言的RPC服務治理架構,快、易用卻功能強大,性能遠遠高于 Dubbo、Motan、Thrift等架構,是gRPC性能的兩倍。
https://rpcx.io/ https://github.com/smallnest/rpcx6、搜狗之srpc
Sogou基于Workflow的自研RPC架構,C++實作
https://github.com/sogou/srpc-- RPC based on Sogou C++ Workflow
https://github.com/sogou/workflow-- Sogou’s C++ Asynchronous Programming Engine
https://www.zhihu.com/people/liyingxin1412/其它小衆的開源C++ RPC
1. RCF: 純c++的RPC, 不引入IDL, 大量用到boost,比較強大.
2. casocklib: protobuf + asio 較完善實作
3. eventrpc: protobuf + libevent 較完善實作
https://www.exit1.org/Event-RPC/4. evproto: protobuf + libevent 簡單實作
https://github.com/chenshuo/evproto https://github.com/chenshuo/evproto25. febird:同樣無IDL的c++ RPC,自己實作了串行化和網絡IO.
6. libHttp, xmlrpc 都是xml封裝的RPC
7.rest_rpc
https://github.com/topcpporg/rest_rpc8.muduo_rpc
https://github.com/chenshuo/muduo-protorpc https://github.com/chenshuo/muduo/tree/master/examples/protobuf9.other
https://github.com/IronsDu/gayrpc https://github.com/guangqianpeng/jrpc https://github.com/hjk41/tinyrpc https://github.com/button-chen/buttonrpc_cpp14 https://github.com/persistentsnail/easy_pb_rpc一個基于protocol buffer的RPC實作
http://www.cnblogs.com/persistentsnail/p/3458342.htmljava rpc
java,一起寫rpc架構
https://blog.csdn.net/linuu/article/category/6362083