什么是rpc框架
先回答第一個問題:什么是RPC框架? 如果用一句話概括RPC就是:遠程調用框架(Remote Procedure Call)

那什么是遠程調用?
通常我們調用一個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
https://github.com/grpc/grpc
https://github.com/google/protobuf
http://doc.oschina.net/grpc
2、thrift
http://thrift.apache.org/
http://thrift.apache.org/lib/
http://thrift.apache.org/lib/cpp
https://github.com/apache/thrift
3、Tencent
騰訊微服務框架Tars介紹
https://github.com/TarsCloud/Tars
https://github.com/TarsCloud/TarsCpp
https://github.com/TarsCloud/TarsGo
https://github.com/loveyacper/ananas
https://github.com/Tencent/phxrpc,前身是Svrkit
4、Baidu
https://github.com/brpc/brpc
5、golang
http://rpcx.site/ -- 最好的Go語言的RPC服務治理框架,快、易用卻功能強大,性能遠遠高於 Dubbo、Motan、Thrift等框架,是gRPC性能的兩倍
https://github.com/smallnest/rpcx
若干開源的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/evproto2
5. febird:同樣無IDL的c++ RPC,自己實現了串行化和網絡IO.
6. libHttp, xmlrpc 都是xml封裝的RPC
7.rest_rpc
https://github.com/topcpporg/rest_rpc
8.muduo_rpc
https://github.com/chenshuo/muduo-protorpc
https://github.com/chenshuo/muduo/tree/master/examples/protobuf
9.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.html 一個基於protocol buffer的RPC實現
---------------------
作者:libaineu2004
來源:CSDN
原文:https://blog.csdn.net/libaineu2004/article/details/80117847
版權聲明:本文為博主原創文章,轉載請附上博文鏈接!
