基於protobuf的RPC實現

2021-07-05 06:54:03 字數 3616 閱讀 9010

可以對照使用google protobuf rpc實現echo service一文看,細節本文不再描述。

google protobuf只負責訊息的打包和解包,並不包含rpc的實現,但其包含了rpc的定義。假設有下面的rpc定義:

service

myservice

那麼要實現這個rpc需要最少做哪些事?總結起來需要完成以下幾步:

rpc客戶端需要實現google::protobuf::rpcchannel。主要實現rpcchannel::callmethod介面。客戶端呼叫任何乙個rpc介面,最終都是呼叫到callmethod。這個函式的典型實現就是將rpc呼叫引數序列化,然後投遞給網路模組進行傳送。

void

callmethod

(const

::google

::protobuf

::methoddescriptor

*method,::

google

::protobuf

::rpccontroller

*controller

,const

::google

::protobuf

::message

*request,::

google

::protobuf

::message

*response,::

google

::protobuf

::closure

*done

)

服務端首先需要實現rpc介面,直接實現myservice中定義的介面:

class

myserviceimpl

:public

myservice

}

基於以上,可以看出服務端根本不知道客戶端想要呼叫哪乙個rpc介面。從伺服器接收到網路訊息,到呼叫到myserviceimpl::echo還有很大一段距離。

解決方法就是在網路訊息中帶上rpc介面標識。這個標識可以直接帶上service name和method name,但這種實現導致網路訊息太大。另一種實現是基於service name和method name生成乙個雜湊值,因為介面不會太多,所以較容易找到基本不衝突的字串雜湊演算法。

無論哪種方法,伺服器是肯定需要建立rpc介面標識到protobuf service物件的對映的。

這裡提供第三種方法:基於option的方法。

protobuf中option機制類似於這樣一種機制:service&method被視為乙個物件,其有很多屬性,屬性包含內建的,以及使用者擴充套件的。使用者擴充套件的就是option。每乙個屬性有乙個值。protobuf提供訪問service&method這些屬性的介面。

首先擴充套件service&method的屬性,以下定義這些屬性的key:

extend

google

.protobuf

.serviceoptions

extend

google

.protobuf

.methodoptions

應用層定義service&method時可以指定以上key的值:

service

myservice

rpcecho_2

(echoreqmsg

)returns

(echorespmsg

)...

}

以上相當於在整個應用中,每個service都被賦予了唯一的id,單個service中的method也有唯一的id。

然後可以通過protobuf取出以上屬性值:

void

callmethod

(const

::google

::protobuf

::methoddescriptor

*method,::

google

::protobuf

::rpccontroller

*controller

,const

::google

::protobuf

::message

*request,::

google

::protobuf

::message

*response,::

google

::protobuf

::closure

*done

)

考慮到serviceidmethodid的範圍,可以直接打包到乙個32位整數裡:

uint32_t ret = (serviceid << 16) | methodid;
然後就可以把這個值作為網路訊息頭的一部分傳送。

當然伺服器端是需要建立這個標識值到service的對映的:

bool

myrpcserver

::registerservice

(google

::protobuf

::service

*rpcservice

)return

true

;}

服務端收到rpc呼叫後,取出這個標識值,然後再從_rpccallmap中取出對應的service和method,最後進行呼叫:

google

::protobuf

::message

*response

=_pservice

->

getresponseprototype

(_pmethoddes

).new

();// 用於回應的closure

rpcserverclosure

*pclosure

=new

(nothrow

)rpcserverclosure

(_channelid

,_pconnection

,_preqmsg

,presmsg

,_messagecodec

,_version

);rpccontroller

*pcontroller

=pclosure

->

getrpccontroller

();...

// protobuf 生成的callmethod,會自動呼叫到echo介面

_pservice

->

callmethod

(_pmethoddes

,pcontroller

,_preqmsg

,presmsg

,pclosure

);

RESTful還是基於HTTP的RPC實現

比如說,這個restful風格。從網上的資料大概知道,它首次出現在 2000 年 roy fielding 的博士 中,他是 http 規範的主要編寫者之一。對於http來作為通訊,我認為是乙個不錯的方案,因為目前大多語言的標準庫應該都是提供了http的支援,而且http這種無狀態的請求,也容易接受...

基於MQTT的RPC協議

rpc 是一種基於request response 模式的分布式協議。而mqtt 是基於pub sub模式的協議。是否能夠將這兩種協議相結合,實現rpc over mqtt 我並沒有發現由比較知名的rpc over mqtt協議。於是,自己著手設計乙個極簡的rpc over mqtt 協議。本文介紹...

RabbitMQ 基於RPC實現

對於使用rabbitmq執行command的情況,有時候需要有返回值資訊。此時相當於client發布乙個command後,並偵聽返回結果的queue,server接收並處理,將處理結果發布到client偵聽的queue中。簡單實現如下 1.client端 private static void rp...