gRPC 是由google提供的rpc開發框架,什麼是RPC呢(remote procedure call), rc--遠程調用,平常調用web服務器的api就是遠程調用的一種,假如p理解爲函數,就是說像調用本地函數同樣調用遠程的函數,rpc框架就是提供一套調用方(client)與被調用方(server)的工具設施和代碼庫用以方便的達到rpc目標。java
本文一方面用簡單的例子(在官方實例上增刪)來闡述grpc的使用,並輔以 protobuffer 的實例,另外一方面有別於傳統的入門文將調用方和被調用方使用一樣的語言和環境,本例調用方本機使用python,服務端使用node並部署於linux虛擬機。這樣指望將整個流程描述的更清晰些。node
本文讀者對象:初中級 web後端開放人員,指望瞭解protocol buffer、rpc,grpc使用或感興趣的同窗python
調用方(client),windows 10,安裝標準Python , pb工具和 grpc框架.python -m pip install grpcio
python -m pip install grpcio_tools
文檔上都寫着grpc_tools 而包名倒是 grpcio_tools 憑增一段小曲折 linux
被調用方(server),debian8.9, 安裝node ,pb工具和 grpc框架
debian上參考官網的,直接從git下載,除了包含庫外還在 examples 目錄下有實例.apt-get install -y git
git clone -b v1.25.0 https://github.com/grpc/grpc
git
既然涉及跨服務器調用,那就須要定義數據傳輸和過程定義格式,咱們都知道,使用xml 或者json 等格式均可以達到此目的,既然都grpc了,那就繞不開同時google出品的 pb格式, "Protocol buffers are a flexible, efficient, automated mechanism for serializing structured data – think XML, but smaller, faster, and simpler." 須要瞭解詳情的可參考 protocol官方文檔github
syntax = 'proto3' ; option java_package = 'io.grpc.examples'; package helloworld; service Greeter{ rpc SayHello(HelloRequest) returns (HelloReply){} rpc SendIm(ImMsg) returns (ImRet){} } message HelloRequest{ string name = 1; } message HelloReply{ string message = 1; } message ImMsg{ int32 fromuser = 1; int32 touser = 2; string content = 3; string faces = 16; string imgs = 17; } message ImRet{ int32 retcode = 1; string retmsg = 2; string extdata = 16; string errmsg = 17; }
以上就是咱們定義的一個簡單的 helloworld.proto 文件,它定義了兩個過程(函數),一個是官方的SayHello,一個是本例新增的發送 IM消息SendIM,隨之定義了兩個消息結構,im發送消息 和 發送消息後的服務端返回結構 ImRetweb
client python 端:python -m grpc_tools.protoc -I ./protos --python_out=. --grpc_python_out=. ./protos/helloworld.proto
以上命令注意文件得目錄路徑。執行後會在本目錄生成兩個文件,分別是pb和grpc的代碼文件npm
server nodejs 端:
nodejs 使用grpc框架有兩種方式,靜態和動態引入,所謂靜態就是像上面同樣提早生成 pb的文件和gprc的文件,動態就是直接在代碼中讀取.proto 文件,由框架在讀入後自動編譯,我偷懶使用靜態載入可跳過下面。npm install -g grpc-tools
安裝可能會失敗,錯誤以下:
權限不足,上網搜找到 npm安裝權限問題,
補充命令參數 npm install --unsafe-perm grpc_tools
而後
grpc_tools_node_protoc --js_out=import_style=commonjs,binary:../node/static_codegen/ --grpc_out=../node/static_codegen --plugin=protoc-gen-grpc=`which grpc_tools_node_protoc_plugin` helloworld.protojson
grpc_tools_node_protoc --js_out=import_style=commonjs,binary:../node/static_codegen/route_guide/ --grpc_out=../node/static_codegen/route_guide/ --plugin=protoc-gen-grpc=`which grpc_tools_node_protoc_plugin` route_guide.protowindows
本例所用代碼皆由官方示例編輯,爲了減少文章長度和無用代碼量,特地去掉了收尾和註釋,如侵權或形成讀者不適本人深表歉意
client端
import grpc import helloworld_pb2_grpc import helloworld_pb2 def run(): channel = grpc.insecure_channel('192.168.220.129:50051') stub = helloworld_pb2_grpc.GreeterStub(channel) response = stub.SayHello(helloworld_pb2.HelloRequest(name='you')) print("Greeter client received: " + response.message) response = stub.SendIm(helloworld_pb2.ImMsg(fromuser=2059, touser=3088, content='轉帳收到了嗎?[#F]', faces='賣萌表情')) print("sendmsg response data:\n", response) run()
注意生成的兩個py文件和本代碼文件放在同級目錄. 成功運行結果:
server端
const PROTO_PATH = __dirname + '/../../protos/helloworld.proto'; const grpc = require('grpc'); const protoLoader = require('@grpc/proto-loader'); let packageDefinition = protoLoader.loadSync( PROTO_PATH, {keepCase: true, longs: String, enums: String, defaults: true, oneofs: true }); let hello_proto = grpc.loadPackageDefinition(packageDefinition).helloworld; /** * Implements the SayHello RPC method. */ function sayHello(call, callback) { callback(null, {message: 'Hello ' + call.request.name}); } /** add by lwy for demo */ function sendIm(call,callback){ console.log(call.request); callback(null,{retcode:10100,retmsg:"send suc"}); } function main() { var server = new grpc.Server(); //server.addService(hello_proto.Greeter.service, {sayHello: sayHello}); server.addService(hello_proto.Greeter.service, {sayHello: sayHello,sendIm: sendIm}); server.bind('0.0.0.0:50051', grpc.ServerCredentials.createInsecure()); server.start(); } main();
成功運行截圖:
整個過程是清晰的,可是完整執行起來仍是容易磕碰掉坑。
當年咱們使用vs開發webservice 時,服務端寫好以後,直接在調用方右鍵添加引用(類比引入包),客戶端就將全部的代碼和數據生成好了,直接像本地調用函數便可。ms就是這樣貼心。 而grpc我理解爲分了三步(三層),定義數據和過程,運用工具鏈生成,編寫代碼。
這樣減小了開發協做流暢度,可是程序效率很是高,一方面文本的pb格式在兩端都會被編譯後再使用,這讓數據的序列化和反序列化效率很是高,另外一方面它採用自定義二進制編碼,數據佔據空間小保證高頻網絡調用時節省大量數據傳輸。若是要達到深刻的使用, protocal buffer的深刻學習必不可少,光它的指南就是一本小冊子,還有 grpc自己框架的學醫成本,so, 增長了不小時間成本
綜上,若是你的項目須要高頻的遠程調用(1s至少百級別以上),而且傳輸的數據相對豐富,那麼grpc棧是一個很是高效的可選方案, 否則的話,使用普通的微服務框架或常規http restful服務會讓開發使用更便捷。