基于protobuf的RPC实现
可以比较使用google protobuf RPC实现echo service可见。述。
google protobuf仅仅负责消息的打包和解包。并不包括RPC的实现。但其包括了RPC的定义。如果有以下的RPC定义:
service MyService {
rpc Echo(EchoReqMsg) returns(EchoRespMsg)
}
那么要实现这个RPC须要最少做哪些事?总结起来须要完毕下面几步:
client
RPCclient须要实现google::protobuf::RpcChannel。主要实现RpcChannel::CallMethod接口。client调用不论什么一个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) {
...
DataBufferOutputStream outputStream(...) // 取决于你使用的网络实现
request->SerializeToZeroCopyStream(&outputStream);
_connection->postData(outputStream.getData(), ...
...
}
服务端
服务端首先须要实现RPC接口。直接实现MyService中定义的接口:
class MyServiceImpl : public MyService {
virtual void Echo(::google::protobuf::RpcController* controller,
const EchoReqMsg* request,
EchoRespMsg* response,
::google::protobuf::Closure* done) {
...
done->Run();
}
}
标示service&method
基于以上,能够看出服务端根本不知道client想要调用哪一个RPC接口。
从server接收到网络消息。到调用到MyServiceImpl::Echo还有非常大一段距离。
解决方法就是在网络消息中带上RPC接口标识。
这个标识能够直接带上service name和method name,但这样的实现导致网络消息太大。还有一种实现是基于service name和method name生成一个哈希值,由于接口不会太多,所以较easy找到基本不冲突的字符串哈希算法。
不管哪种方法,server是肯定须要建立RPC接口标识到protobuf service对象的映射的。
这里提供第三种方法:基于option的方法。
protobuf中option机制类似于这样一种机制:service&method被视为一个对象,其有非常多属性,属性包括内置的,以及用户扩展的。用户扩展的就是option。每个属性有一个值。protobuf提供訪问service&method这些属性的接口。
首先扩展service&method的属性。下面定义这些属性的key:
extend google.protobuf.ServiceOptions {
required uint32 global_service_id = 1000;
}
extend google.protobuf.MethodOptions {
required uint32 local_method_id = 1000;
}
应用层定义service&method时能够指定以上key的值:
service MyService
{
option (arpc.global_service_id) = 2302; rpc Echo(EchoReqMsg) returns(EchoRespMsg)
{
option (arpc.local_method_id) = 1;
}
rpc Echo_2(EchoReqMsg) returns(EchoRespMsg)
{
option (arpc.local_method_id) = 2;
}
...
}
以上相当于在整个应用中。每一个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) {
...
google::protobuf::ServiceDescriptor *service = method->service();
uint32_t serviceId = (uint32_t)(service->options().GetExtension(global_service_id));
uint32_t methodId = (uint32_t)(method->options().GetExtension(local_method_id));
...
}
考虑到serviceId methodId的范围,能够直接打包到一个32位整数里:
uint32_t ret = (serviceId << 16) | methodId;
然后就能够把这个值作为网络消息头的一部分发送。
当然server端是须要建立这个标识值到service的映射的:
bool MyRPCServer::registerService(google::protobuf::Service *rpcService) {
const google::protobuf::ServiceDescriptor = rpcService->GetDescriptor();
int methodCnt = pSerDes->method_count();
for (int i = 0; i < methodCnt; i++) {
google::protobuf::MethodDescriptor *pMethodDes = pSerDes->method(i);
uint32_t rpcCode = PacketCodeBuilder()(pMethodDes); // 计算出映射值
_rpcCallMap[rpcCode] = make_pair(rpcService, pMethodDes); // 建立映射
}
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);
參考
原文地址: http://codemacro.com/2014/08/31/protobuf-rpc/
written by Kevin Lynx posted at
http://codemacro.com
版权声明:本文博客原创文章,博客,未经同意,不得转载。
基于protobuf的RPC实现的更多相关文章
- RPC框架实现(一) Protobuf的rpc实现
概述 RPC框架是云端服务基础框架之一,负责云端服务模块之间的项目调用,类似于本地的函数调用一样方便.常见的RPC框架配带的功能有: 编解码协议.比如protobuf.thrift等等. 服务发现.指 ...
- 基于HTTP/2和protobuf的RPC框架:GRPC
谷歌发布的首款基于HTTP/2和protobuf的RPC框架:GRPC Google 刚刚开源了grpc, 一个基于HTTP2 和 Protobuf 的高性能.开源.通用的RPC框架.Protobu ...
- 基于Protobuf的分布式高性能RPC框架——Navi-Pbrpc
基于Protobuf的分布式高性能RPC框架——Navi-Pbrpc 二月 8, 2016 1 简介 Navi-pbrpc框架是一个高性能的远程调用RPC框架,使用netty4技术提供非阻塞.异步.全 ...
- 基于Netty打造RPC服务器设计经验谈
自从在园子里,发表了两篇如何基于Netty构建RPC服务器的文章:谈谈如何使用Netty开发实现高性能的RPC服务器.Netty实现高性能RPC服务器优化篇之消息序列化 之后,收到了很多同行.园友们热 ...
- 基于kryonet的RPC,使用kryo进行序列化
Kryo是一个序列化框架. Kryonet是一个基于kryo的RPC框架,它实现了一套高效简洁的API,它通过NIO实现了TCP和UDP通讯,目前还不支持Http. 自己写了一个测试代码,运行了下,感 ...
- github上的golang双向rpc,基于原生“net/rpc”库实现,可以注册回调
github上的golang双向rpc,基于原生“net/rpc”库实现,可以注册回调.仅支持一个server和一个client交互. 地址:https://github.com/rocket049/ ...
- 基于Netty的RPC简易实现
代码地址如下:http://www.demodashi.com/demo/13448.html 可以给你提供思路 也可以让你学到Netty相关的知识 当然,这只是一种实现方式 需求 看下图,其实这个项 ...
- 十七.protobuf在rpc中的使用
关于protobuf在rpc中的使用,设计到gRPC,相关内容待续....
- 这样基于Netty重构RPC框架你不可能知道
原创申明:本文由公众号[猿灯塔]原创,转载请说明出处标注 今天是猿灯塔“365天原创计划”第5天. 今天呢!灯塔君跟大家讲: 基于Netty重构RPC框架 一.CyclicBarrier方法说明 1. ...
随机推荐
- UVA 847 - A Multiplication Game(游戏)
UVA 847 - A Multiplication Game 题目链接 题意:一个数一開始是1,每次轮流乘2-9,谁先大于n谁就赢,问谁胜 思路:博弈,找出必胜态.2-9为stan,10-18为ol ...
- LINQ之路(2):LINQ to SQL本质
LINQ之路(2):LINQ to SQL本质 在前面一篇文章中回顾了LINQ基本语法规则,在本文将介绍LINQ to SQL的本质.LINQ to SQL是microsoft针对SQL Server ...
- LVM pvcreate,vgcreate,lvcreate,mkfs
首先介绍LVM的几个概念: 1. 物理卷Physical volume (PV):可以在上面建立卷组的媒介,可以是硬盘分区,也可以是硬盘本身或者回环文件(loopback file).物理卷包 ...
- mysql经常使用命令总结
MySQL经常使用指令(备查) 最经常使用的显示命令: 1.显示数据库列表. show databases; 2.显示库中的数据表: use mysql; show tables; 3.显示数 ...
- SQL Server安全性专题一:简介
原文:SQL Server安全性专题一:简介 一. 安全威胁与法则 1. 安全定义 2. 安全威胁 3. 安全法则 安全定义: 在SQLServer环境中,安全性可以认为是[数据保护].包括: 数 ...
- UVA 10529 Dumb Bones 可能性dp 需求预期
主题链接:点击打开链接 题意: 要在一条直线上摆多米诺骨牌. 输入n, l, r 要摆n张排,每次摆下去向左倒的概率是l, 向右倒的概率是r 能够採取最优策略.即能够中间放一段.然后左右两边放一段等, ...
- (大数据工程师学习路径)第四步 SQL基础课程----约束
一.简介 约束是一种限制,它通过对表的行或列的数据做出限制,来确保表的数据的完整性.唯一性.本节实验就在操作中熟悉MySQL中的几种约束. 二.内容 1.约束分类 听名字就知道,约束是一种限制,它通过 ...
- Online网站集
http://tool.oschina.net/apidocs/ 在线工具(IT技术工具)
- 客房收费系统改造(三)—厂+反射+DAL
前一段时间有一个简单的三登录功能实现窗口,心灵修养一点点,但很快就被泼了一盆冷水.房费是不可能做到在短短三年,假设你使用三个,这倒房费三个功能必须使用函数来实现.了七层的研究. 经过一个星期的看博客. ...
- 5、VS2010+ASP.NET MVC4+EF4+JqueryEasyUI+Oracle该项目的开发——使用datagrid做报表
来点需要:我使用的数据库访问EF框架,但是,因为使用一个动态表来的统计报告中.单独是每天产生基于数据表,它是很难使用EF加盟前.所以我包装在两组数据库存取层的框内,一个是EF,一种是传统的ADO.NE ...