微信开源C/C++ RPC框架PhxRPC
来源:互联网 发布:视频点播php源码 编辑:程序博客网 时间:2024/05/01 16:29
PhxRPC是微信后台团队推出的一个非常简洁小巧的RPC框架,编译生成的库只有450K。
开源地址:
https://github.com/tencent-wechat/phxrpc
点击阅读原文可自动跳转到github地址
总览
使用Protobuf作为IDL用于描述RPC接口以及通信数据结构。
基于Protobuf文件自动生成Client以及Server接口,用于Client的构建,以及Server的实现。
半同步半异步模式,采用独立多IO线程,通过Epoll管理请求的接入以及读写,工作线程采用固定线程池。IO线程与工作线程通过内存队列进行交互。
提供完善的过载保护,无需配置阀值,支持动态自适应拒绝请求。
提供简易的Client/Server配置读入方式。
基于lambda函数实现并发访问Server,可以非常方便地实现Google提出的 Backup Requests 模式。
局限
不支持多进程模式。
性能
使用Sample目录下的Search RPC C/S进行Echo RPC调用的压测,相当于Worker空转情况。
运行环境
CPU:24 x Intel(R) Xeon(R) CPU E5-2620 v3 @ 2.40GHz内存:32 GB网卡:千兆网卡Client/Server机器之间PING值: 0.05ms请求写入并发:1000个线程业务数据大小:除去HTTP协议部分20bWorker线程数:20
性能测试结果(qps)
短连接
长连接
如何使用
编写proto文件
下面是sample目录下的proto文件样例。
syntax = "proto3";package search;import "google/protobuf/wrappers.proto";import "google/protobuf/empty.proto";import "phxrpc/phxrpc.proto";enum SiteType { BLOG = 0; NEWS = 1; VIDEO = 2; UNKNOWN = 3;}message Site { string url = 1; string title = 2; SiteType type = 3; tring summary = 4;}message SearchRequest { string query = 1;}message SearchResult { repeated Site sites = 1;}service Search{ rpc Search( SearchRequest ) returns( SearchResult ) { option( phxrpc.CmdID ) = 1; option( phxrpc.OptString ) = "q:"; option( phxrpc.Usage ) = "-q <query>"; } rpc Notify( google.protobuf.StringValue ) returns( google.protobuf.Empty ) { option( phxrpc.CmdID ) = 2; option( phxrpc.OptString ) = "m:"; option( phxrpc.Usage ) = "-m <msg>"; } }
生成代码
(PhxRPC根目录)/codegen/phxrpc_pb2server -I (PhxRPC根目录) -I (Protobuf include目录) -f (proto文件路径) -d (生成代码放置路径)
#sample
../codegen/phxrpc_pb2server -I ../ -I ../third_party/protobuf/include -f search.proto -d .
调用完工具后,在生成代码放置目录下执行make,即可生成全部的RPC相关代码。
选择是否启用boost优化
打开生成代码放置目录下的Makefile文件。
#choose to use boost for network
#LDFLAGS := $(PLUGIN_BOOST_LDFLAGS) $(LDFLAGS)
可以看到以上两行,取消注释掉第二行,重新make clean, make即可开启boost对PhxRPC的优化。开启前记得编译好PhxRPC的boost插件。
补充自己的代码
Server(xxx_service_impl.cpp)
int SearchServiceImpl :: PHXEcho( const google::protobuf::StringValue & req, google::protobuf::StringValue * resp ) { resp->set_value( req.value() ); return 0;}int SearchServiceImpl :: Search( const search::SearchRequest & req, search::SearchResult * resp ) { //这里补充这个RPC调用的Server端代码 return -1; }int SearchServiceImpl :: Notify( const google::protobuf::StringValue & req, google::protobuf::Empty * resp ) { //这里补充这个RPC调用的Server端代码 return -1; }
Client (xxx_client.cpp)
//这个是默认生成的代码, 可自行修改,或利用我们提供的stub API自定义封装Clientint SearchClient :: PHXEcho( const google::protobuf::StringValue & req, google::protobuf::StringValue * resp ){ const phxrpc::Endpoint_t * ep = global_searchclient_config_.GetRandom(); if(ep != nullptr) { phxrpc::BlockTcpStream socket; bool open_ret = phxrpc::PhxrpcTcpUtils::Open(&socket, ep->ip, ep->port, global_searchclient_config_.GetConnectTimeoutMS(), NULL, 0, *(global_searchclient_monitor_.get())); if ( open_ret ) { socket.SetTimeout(global_searchclient_config_.GetSocketTimeoutMS()); SearchStub stub(socket, *(global_searchclient_monitor_.get())); return stub.PHXEcho(req, resp); } } return -1; }
Client并发调用样例
int SearchClient :: PhxBatchEcho( const google::protobuf::StringValue & req, google::protobuf::StringValue * resp ){ int ret = -1; size_t echo_server_count = 2; uthread_begin; for (size_t i = 0; i < echo_server_count; i++) { uthread_t [=, &uthread_s, &ret](void *) { const phxrpc::Endpoint_t * ep = global_searchclient_config_.GetByIndex(i); if (ep != nullptr) { phxrpc::UThreadTcpStream socket; if(phxrpc::PhxrpcTcpUtils::Open(&uthread_s, &socket, ep->ip, ep->port, global_searchclient_config_.GetConnectTimeoutMS(), *(global_searchclient_monitor_.get()))) { socket.SetTimeout(global_searchclient_config_.GetSocketTimeoutMS()); SearchStub stub(socket, *(global_searchclient_monitor_.get())); int this_ret = stub.PHXEcho(req, resp); if (this_ret == 0) { ret = this_ret; uthread_s.Close(); } } } }; } uthread_end; return ret;}
uthread_begin
, uthread_end
, uthread_s
, uthread_t
这几个关键字是PhxRPC自定义的宏,分别表示协程的准备,结束,协程调度器以及协程的创建。
上面的代码实现了Google提出的 Backup Requests 模式。实现的功能是分别对两个Server同时发起Echo调用,当有一个Server响应的时候,则整个函数结束。在这段代码里面,我们提供了一种异步IO的同步写法,并给予了一些方便使用的宏定义。首先使用uthread_begin
进行准备,然后使用uthread_t
以lambda的形式创建一个协程,而在任意一个协程里面都可使用我们PhxRPC生成的Client API进行RPC调用,并可使用uthread_s
随时结束所有RPC调用。最后的uthread_end
真正通过协程调度发起这些lambda内的RPC调用,并等待结束。
当然你可以借用这4个宏定义,以同步代码的写法,进行更自定义的并发访问。
Server配置说明 (xxx_server.conf)
[Server]BindIP = 127.0.0.1 //Server IPPort = 16161 //Server PortMaxThreads = 16 //Worker 线程数IOThreadCount = 3 //IO线程数,针对业务请自行调节PackageName = search //Server 名字,用于自行实现的监控统计上报MaxConnections = 800000 //最大并发连接数MaxQueueLength = 20480 //IO队列最大长度FastRejectThresholdMS = 20 //快速拒绝自适应调节阀值,建议保持默认20ms,不做修改[ServerTimeout]SocketTimeoutMS = 5000 //Server读写超时,Worker处理超时
- 微信开源C/C++ RPC框架PhxRPC
- RPC for C/C++
- JSON json-rpc-c
- 【C++】【RPC】Win32 RPC 编程(一)
- C语言实现JSON-RPC
- 客户端websocket(C#)长连接及简易RPC框架设计(一)
- 客户端websocket(c#)长连接及简易rpc框架设计(二)
- phxrpc解析
- 【C++】【CPR】浅析远程过程调用 RPC
- 【C++】【CPR】浅析远程过程调用 RPC
- JSN-RPC的C语言实现
- RPC框架
- RPC框架
- RPC 框架
- RPC框架
- RPC框架
- RPC 框架
- RPC框架
- javascript与移动app的交互
- 分表和分区的区别
- tyvj P1051 选课
- Angularjs 到处坑
- 从无到有系列之storm-安装部署01
- 微信开源C/C++ RPC框架PhxRPC
- 数组
- 批量归类文件
- http与websocket的相同点和不同点
- 基于MapboxGL的样式文件自动生成图例
- cocoapods 的安装以及安装中遇到的问题的解决方法-安装RVM
- 重新认识Activity(一)生命周期方法(系统垃圾回收机制和onSaveInstanceState)
- 利用Visual Basic操作XML数据
- 工银二维码,便捷支付中的黑马