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服务会让开发使用更便捷。