天天看點

開源項目推薦:主流RPC開源架構及知識科普

什麼是rpc架構?

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

開源項目推薦:主流RPC開源架構及知識科普

那什麼是遠端調用?

通常我們調用一個php中的方法,比如這樣一個函數方法: localAdd(10, 20),localAdd方法的具體實作要麼是使用者自己定義的,要麼是php庫函數中自帶的,也就說在localAdd方法的代碼實作在本地,它是一個本地調用!

遠端調用意思就是:被調用方法的具體實作不在程式運作本地,而是在别的某個遠端地方。

最早在 Nelson 的論文中指出實作 RPC 的程式包括 5 個理論模型部分:

User

User-stub

RPCRuntime

Server-stub

Server

這 5 個部分的關系如下圖所示:

開源項目推薦:主流RPC開源架構及知識科普

這裡 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/grpc

2、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/thrift

3、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/brpc

5、golang之rpcx

rpcx是一個類似阿裡巴巴 Dubbo 和微網誌 Motan 的分布式的RPC服務架構,基于Golang net/rpc實作。号稱是最好的Go語言的RPC服務治理架構,快、易用卻功能強大,性能遠遠高于 Dubbo、Motan、Thrift等架構,是gRPC性能的兩倍。

https://rpcx.io/ https://github.com/smallnest/rpcx

6、搜狗之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/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

java rpc

java,一起寫rpc架構

https://blog.csdn.net/linuu/article/category/6362083