grpc:google 官方的 rpc 框架

WesFiedler 8年前發布 | 41K 次閱讀 WEB服務/RPC/SOA gRPC

protobuf是在項目中經常會用到的一個庫,它提供了方便的工具和接口,可以對結構化數據進行序列化和反序列化,便于網絡傳輸。

其實,如果將一個函數調用用結構化數據表示出來,利用protobuf序列化后通過網絡傳遞到遠端,在遠端進行反序列化解析,就自然地實現了rpc(Remote Procedure Call)的功能。

protobuf中保留了關鍵字rpc,并且提供了一個RpcChannel的類,供開發者自己實現rpc框架。實現這個rpc框架,其實主要是實現RpcChannel::CallMethod這個接口。我們自己的項目中,就使用了一套自己實現的基于ansyncore的RpcChannel,而某度最近也開源了其基于protobuf的 rpc框架 ,網絡部分是使用的Boost::Asio,有興趣的讀者可以自行前往其github wiki頁面學習。

那grpc呢,則是google自己基于protobuf(也是google自己開發的庫)實現的一套rpc框架。這里使用一張官網的圖,表示下其基礎架構:

一個簡單的例子

可能光說不練有點抽象,那么下面用一個例子說明下grpc的基本用法。

說到網絡相關的例子,簡單而又實用的當屬EchoServer了。

定義一個EchoServer只需一個接口Echo,它接受一條字符串消息,并原樣返回一條字符串消息。因此,echo_server.proto文件定義如下:

syntax = "proto3";

package echo_server;

service EchoServer
{
    rpc Echo (EchoRequest) returns (EchoReply) {}
}

message EchoRequest
{
    string msg = 1;
}

message EchoReply
{
    string msg = 1;
}

首先,grpc使用protobuf3.x版本,因此需要在開頭聲明syntax=”proto3”,剩下的部分和c語言的語法很類似,基本上有了例子之后,照貓畫虎很容易就可以寫出來自己需要的proto文件。

有了proto文件之后,需要使用protoc將其編譯生成對應的py文件。這里grpc提供了一個grpc_tools的庫,可以將這一過程程序化:

from grpc.tools import protoc

protoc.main(
    (
        '',
        '-I.',
        '--python_out=.',
        '--grpc_python_out=.',
        './echo_server.proto',
    )
)

生成的echo_server_pb2.py文件中,就定義了我們實現這個EchoServer所需的Servicer類和Stub類。

Server

先看server的實現。

首先,需要定義一個類,繼承自xxxServicer(這里是EchoServerServicer),并重寫其Echo方法。

class EchoServer(echo_server_pb2.EchoServerServicer):
    def Echo(self, request, context):
        return echo_server_pb2.EchoReply(msg='echo:%s' % request.msg)

可以看到,其中的request和return值,都是按照我們在proto文件中的定義生成的python類型,非常直觀。

如何將這個EchoServer類和rpc服務綁定在一起,也是有套路的:

server = grpc.server(futures.ThreadPoolExecutor(max_workers=10))
echo_server_pb2.add_EchoServerServicer_to_server(EchoServer(), server)
server.add_insecure_port('[::]:50015')
server.start()
try:
    while True:
        time.sleep(60*60)
except KeyboardInterrupt:
    server.stop(0)

由于server.start()是一個非阻塞式調用,因此需要在后面用一個死循環來防止程序終止/GC導致rpc服務不可用。

Client

Client的實現就更簡單了,只需通過ip和port創建一個channel,然后利用這個channel創建一個本地的Stub,然后就可以直接Stub.Echo調用遠端的Echo方法了,Stub會幫你處理好一切其他事務(構造調用的結構化數據,序列化,網絡傳輸等等)。

from __future__ import print_function
import grpc
import echo_server_pb2
import sys

if sys.version_info.major == 3:
    raw_input = input
else:
    raw_input = raw_input


def run():
    channel = grpc.insecure_channel('localhost:50015')
    stub = echo_server_pb2.EchoServerStub(channel)
    while True:
        msg = raw_input('you say:')
        reply = stub.Echo(echo_server_pb2.EchoRequest(msg=msg))
        print(reply.msg)
    pass

if __name__ == "__main__":
    run()

這段代碼中對print和raw_input這兩個py2和py3不兼容的調用打了Monkey Patch,從而使得這段程序可以同時運行在py2和py3的環境中~

總結

至此,grpc的最基礎的應用就說的差不多了。除了上面的阻塞式調用,grpc還提供了非阻塞式調用(future)。另外,對于傳遞的參數和返回值,grpc還支持流式參數(stream、yield)。具體的相關例子,有興趣的讀者可以前往grpc的官網查詢。

接下來,我將會使用grpc做一個message hub的應用,功能上應該可以替代目前項目中使用的hub(性能上就不指望替代了,畢竟當前hub使用c++實現的),當作一個練手的實際項目。

 

 

來自:http://blog.guoyb.com/2016/10/15/grpc/

 

 本文由用戶 WesFiedler 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!