编程技术开发和娱乐网址导航

网站首页 > 技术文章 正文

远程调用中,rpc到底比http好在哪里

luoxia7 2024-09-30 23:37:23 技术文章 2 ℃ 0 评论




ProtoBuffer的介绍

google有一款非常高效的数据传输格式框架ProtoBuffer。在java中使用protobuffer作为序列化效率比jdk自身的serializable接口效率高的多(github上有个对于序列号性能的研究https://github.com/eishay/jvm-serializers/wiki),这在缓存的时候效率非常高。当然,如此优秀的数据格式框架并不是仅仅使用在缓存上的,既然压缩(姑且将其简单理解为压缩算法吧)如此高效,那么使用在网络IO传输中比JSON或许XML而言效率也为提升很多吧。

gRPC的介绍

gRPC是google开发的一款RPC框架,RPC Server与RPC Clinet之间的数据传输就是刚刚提到的ProtoBuffer,并且该RPC框架还是基于HTTP2的。因此,HTTP2的多路复用,基于流的传输在gRPC上也有相应的实现。

ProtoBuffer格式的定义

PrototBuffer的官方文档:https://developers.google.com/protocol-buffers/docs/proto3

笔者贴出在实际使用中的格式定义文件.proto:

syntax = "proto3";
 
package vsig;
 
service VSIGProto {
 rpc setAcl (ACLRequest) returns (Reply) {}
 rpc openNtp (NTPConfig) returns (Reply) {}
}
message ACLRequest {
 string extranetIp = 1;
 int32 devType = 2;
 string intranetIp = 3;
}
message InterfaceInfoRequest {
 string name =1;
 string ip = 2;
 string mask=3;
 string gateway=4;
}
message NTPInfoRequest{
 bool state = 1;
 string ntpServerIp =2;
 int32 ntpServerPort =3;
}
message NTPConfig{
 NTPInfoRequest ntpInfo = 1;
 InterfaceInfoRequest br0Info = 2;
}
message Reply {
 string message = 1;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32

.proto文件中主要定义了三部分东西:

  • RPC的方法名以及接受的参数和返回的参数
  • RPC方法接受参数的格式
  • RPC方法返回的格式

一个方法仅能接受一个参数,因为笔者定义NTPConfig里面又包含了两个对象,这样保证了openNtp方法仅接收了一个对象

对于定义的message,每个值都有一个唯一的number类型的数字,根据官方文档的解释:它是用于以消息二进制格式标识字段,并且在使用过程中不能随便更改,否则会导致数据无法还原。同时,如果数字定义为1~15则使用一个字节来存储,而16~2047需要使用两个字节来存储。

gRPC Server的实现

定义好.proto之后就可以使用该文件来使用grpc客户端与服务器端了,gRPC的客户端与服务器端必须使用同一个.proto文件

gRPC支持众多常见的编程语言,笔者使用java与node两种语言实现gRPC。

NodeJS gRPC Server实现

package.json:

{
 "name": "grpc-examples",
 "version": "0.1.0",
 "dependencies": {
 "async": "^1.5.2",
 "google-protobuf": "^3.0.0",
 "grpc": "^1.0.0",
 "lodash": "^4.6.1",
 "minimist": "^1.2.0"
 }
}

gRPC服务器的编码实现:

//上述定义的.proto的路径
const PROTO_PATH = '../../vsig.proto';
 
const grpc = require( 'grpc' );
//最后vsig是.proto中的package
const proto = grpc.load( PROTO_PATH ).vsig;
//定义rpc Server的ip与端口
const rpcHost = '127.0.0.1';
const rpcPort = 50051;
 
//定义方法的映射,因为方法最终是在该类中实现的,因此定义改类与.proto中的方法的映射。左边为.proto中的方法名,右边为实现
const methodCover = {
 setAcl: setAcl,
 openNtp: openNTP
};
 
function setAcl( call, callback ) {
 //call.request即为该方法在.proto中定义的参数接收的message对象
 console.log( call.request);
 //该回调即为对客户端的方法,参数1是error,参数二与.proto中方法的返回值对应
 callback( null, {
 message: "rpc call setAcl method success"
 } )
}
 
function openNTP( call, callback ) {
 const ntpInfo = call.request;
 console.log(ntpInfo);
 callback(null,{
 message:"rpc call openNTP call success"
 })
}
function main() {
 var server = new grpc.Server();
 //VSIGProto即为.proto中的server的名称,参数二为方法映射
 server.addProtoService( proto.VSIGProto.service, methodCover );
 const grpcIn = grpc.ServerCredentials.createInsecure();
 //绑定端口
 server.bind( rpcHost + ":" + rpcPort, grpcIn );
 //启动
 server.start();
}
 
main();

Java gRPC Server的实现

gRPC Client的实现

如上定义好服务端之后,将监听指定的端口,客户端只需要对改端口发送请求即可。

Node gRPC Client的实现

const PROTO_PATH = '../vsig.proto';
 
const grpc = require( 'grpc' );
//最后vsig是.proto中的package
const proto = grpc.load( PROTO_PATH ).vsig;
const rpcHost = '127.0.0.1';
const rpcPort = 50051;
//VSIGProto是.proto中service中的VSIGProto
const client = new proto.VSIGProto( rpcHost + ":" + rpcPort, grpc.credentials.createInsecure() );
 
class RpcClient {
 setAcl( acl, cb ) {
 //执行rpc调用
 client.setAcl( acl, function( err, response ) {
 cb( err, response )
 } );
 }
 //封装RPC的方法
 openNTP( ntpconfig, cb ) {
 //执行rpc调用
 client.openNtp( ntpconfig, function( err, response ) {
 cb( err, response );
 } );
 }
}
const rpcClient = new RpcClient();
module.exports = rpcClient;

Tags:

本文暂时没有评论,来添加一个吧(●'◡'●)

欢迎 发表评论:

最近发表
标签列表