欢迎使用CSDN-markdown编辑器
来源:互联网 发布:淘宝上卖的珍珠膏 编辑:程序博客网 时间:2024/06/07 14:17
转载自https://my.oschina.net/u/1050511/blog/751841
简介
sofa-pbrpc是基于Google Protocol Buffers 实现的RPC网络通信库,在百度公司各部门得到广泛使用,每天支撑上亿次内部调用。sofa-pbrpc基于百度大搜索高并发高负载的业务场景不断打磨,成为一套简单易用的轻量级高性能RPC框架。2014年sofa-pbrpc正式对外开源受到广大开发人员的关注,目前sofa-pbrpc已经在浪潮、金山、乐视等各大互联网公司产品中使用。
开源地址:https://github.com/baidu/sofa-pbrpc
目标
- 轻量
- 易用
- 高性能
特性
- 接口简单,容易使用
- 实现高效,性能优异(高吞吐、低延迟、高并发连接数)
- 测试完善,运行稳定
- 支持同步和异步调用,满足不同类型需求
- 支持多级超时设定,灵活控制请求超时时间
- 支持精准的网络流量控制,对应用层透明
- 支持透明压缩传输,节省带宽
- 提供服务和方法级别的服务调用统计信息,方便监控
- 支持自动建立连接和自动重连,用户无需感知连接
- 远程地址相同的Client Stub共享一个连接通道,节省资源
- 空闲连接自动关闭,及时释放资源
- 支持Mock测试
- 支持多Server负载均衡与容错
- 原生支持HTTP协议访问
- 提供内建的Web监控页面
- 提供Python客户端库
- 支持webservice,用户快速定义web server处理逻辑
- 支持profiling,实时查看程序的资源消耗,方便问题追查
快速使用
使用sofa-pbrpc只需要三步:
* 定义通讯协议
* 实现Server
* 实现Client
样例代码参见“sample/echo”。
定义通讯协议
定义协议只需要编写一个proto文件即可。
范例:echo_service.proto
package sofa.pbrpc.test;option cc_generic_services = true;message EchoRequest { required string message = 1;}message EchoResponse { required string message = 1;}service EchoServer { rpc Echo(EchoRequest) returns(EchoResponse);}
使用protoc编译’echo_service.proto’,生成接口文件’echo_service.pb.h’和’echo_service.pb.cc’。
注意:
* package会被映射到C++中的namespace,为了避免冲突建议使用package;
* 需要设置“cc_generic_services”,以通知protoc工具生成RPC框架代码;
* 这里EchoRequest和EchoResponse的成员完全相同,在实际应用中可以设置不同的成员;
实现Server
头文件
#include <sofa/pbrpc/pbrpc.h> // sofa-pbrpc头文件#include "echo_service.pb.h" // service接口定义头文件
实现服务
class EchoServerImpl : public sofa::pbrpc::test::EchoServer{public: EchoServerImpl() {} virtual ~EchoServerImpl() {}private: virtual void Echo(google::protobuf::RpcController* controller, const sofa::pbrpc::test::EchoRequest* request, sofa::pbrpc::test::EchoResponse* response, google::protobuf::Closure* done) { sofa::pbrpc::RpcController* cntl = static_cast<sofa::pbrpc::RpcController*>(controller); SLOG(NOTICE, "Echo(): request message from %s: %s", cntl->RemoteAddress().c_str(), request->message().c_str()); response->set_message("echo message: " + request->message()); done->Run(); }};
注意:
* 服务完成后必须调用done->Run(),通知RPC系统服务完成,触发发送Response;
* 在调了done->Run()之后,Echo的所有四个参数都不再能访问;
done-Run()可以分派到其他线程中执行,以实现了真正的异步处理;
注册和启动服务
int main(){ SOFA_PBRPC_SET_LOG_LEVEL(NOTICE); sofa::pbrpc::RpcServerOptions options; options.work_thread_num = 8; sofa::pbrpc::RpcServer rpc_server(options); if (!rpc_server.Start("0.0.0.0:12321")) { SLOG(ERROR, "start server failed"); return EXIT_FAILURE; } sofa::pbrpc::test::EchoServer* echo_service = new EchoServerImpl(); if (!rpc_server.RegisterService(echo_service)) { SLOG(ERROR, "register service failed"); return EXIT_FAILURE; } rpc_server.Run(); rpc_server.Stop(); return EXIT_SUCCESS;}
实现Client
Client支持同步和异步两种调用方式:
* 同步调用时,调用线程会被阻塞,直到收到回复或者超时;
* 异步调用时,调用线程不会被阻塞,收到回复或者超时会调用用户提供的回调函数;
头文件
#include <sofa/pbrpc/pbrpc.h> // sofa-pbrpc头文件#include "echo_service.pb.h" // service接口定义头文件
同步调用
int main(){ SOFA_PBRPC_SET_LOG_LEVEL(NOTICE); sofa::pbrpc::RpcClientOptions client_options; client_options.work_thread_num = 8; sofa::pbrpc::RpcClient rpc_client(client_options); sofa::pbrpc::RpcChannel rpc_channel(&rpc_client, "127.0.0.1:12321"); sofa::pbrpc::test::EchoServer_Stub stub(&rpc_channel); sofa::pbrpc::test::EchoRequest request; request.set_message("Hello world!"); sofa::pbrpc::test::EchoResponse response; sofa::pbrpc::RpcController controller; controller.SetTimeout(3000); stub.Echo(&controller, &request, &response, NULL); if (controller.Failed()) { SLOG(ERROR, "request failed: %s", controller.ErrorText().c_str()); } return EXIT_SUCCESS;}
异步调用
void EchoCallback(sofa::pbrpc::RpcController* cntl, sofa::pbrpc::test::EchoRequest* request, sofa::pbrpc::test::EchoResponse* response, bool* callbacked){ SLOG(NOTICE, "RemoteAddress=%s", cntl->RemoteAddress().c_str()); SLOG(NOTICE, "IsRequestSent=%s", cntl->IsRequestSent() ? "true" : "false"); if (cntl->IsRequestSent()) { SLOG(NOTICE, "LocalAddress=%s", cntl->LocalAddress().c_str()); SLOG(NOTICE, "SentBytes=%ld", cntl->SentBytes()); } if (cntl->Failed()) { SLOG(ERROR, "request failed: %s", cntl->ErrorText().c_str()); } else { SLOG(NOTICE, "request succeed: %s", response->message().c_str()); } delete cntl; delete request; delete response; *callbacked = true;}int main(){ SOFA_PBRPC_SET_LOG_LEVEL(NOTICE); sofa::pbrpc::RpcClientOptions client_options; sofa::pbrpc::RpcClient rpc_client(client_options); sofa::pbrpc::RpcChannel rpc_channel(&rpc_client, "127.0.0.1:12321"); sofa::pbrpc::test::EchoServer_Stub stub(&rpc_channel); sofa::pbrpc::test::EchoRequest* request = new sofa::pbrpc::test::EchoRequest(); request->set_message("Hello from qinzuoyan01"); sofa::pbrpc::test::EchoResponse* response = new sofa::pbrpc::test::EchoResponse(); sofa::pbrpc::RpcController* cntl = new sofa::pbrpc::RpcController(); cntl->SetTimeout(3000); bool callbacked = false; google::protobuf::Closure* done = sofa::pbrpc::NewClosure( &EchoCallback, cntl, request, response, &callbacked); stub.Echo(cntl, request, response, done); while (!callbacked) { usleep(100000); } return EXIT_SUCCESS;}
注意:
* 异步调用传入的controller、request、response参数,在回调函数执行之前需一直保持有效;
* 回调函数的执行会分配到专门的回调线程中运行,可以通过设置RpcClientOptions的callback_thread_num来配置回调线程数;
实现
系统结构
- RpcClientStream/RpcServerStream:代表client和server之间的连接,用于client和server的网络通信。
- ThreadGroup:client和server内部线程池,用于io操作和执行回调。
- TimeoutManager:采用订阅者模型,对rpc请求进行超时管理。
- RpCListenser:接受来自client的连接请求,创建与client之间的连接。
- ServicePool:server端服务管理与路由。
整个RPC调用经过以下阶段:
- Stub调用RPC函数发起RPC请求.
- RpcChannel调用CallMethod执行RPC调用。
- RpcClient选取RpcClientStream异步发送请求,并添加至超时队列。
- server端RpcListener接收到client的请求,创建对应RpcServerStream。
- RpcServerStream接收数据,根据meta信息在ServerPool中选取对应Service.Method执行。
- server通过RpcServerStream发送执行结果,回复过程与请求过程类似。
技术特点
协议栈方式的网络模型
在sofa-pbrpc中网络数据自上而下流划分为RpcClientStream/RpcServerStream、RpcMessageStream、RpcByteStream三层。消息流层主要负责网络通信相关的操作,操作对象为序列化之后的二机制字节流;消息流层处理的对象是由header、meta和data组装的消息,负责消息级别的控制与统计;协议层负责异步发送接受请求和响应数据。三层结构每一层是下一层的封装和扩展,采用这样协议栈方式的层次划分更加有利于数据协议的扩展。
ZeroCopy方式管理缓冲区。
sofa-pbrpc将内存划分为固定大小的buffer作为缓冲区,对buffer采用引用计数进行管理,减少不必要的内存拷贝。
支持HTTP协议
除了使用原生client访问server外,sofa-pbrpc也支持使用http协议访问server上的服务。同时,用户可以通过使用server端的WebService工具类,快速实现server的对于http请求的处理逻辑。
支持json格式数据传输
sofa-pbrpc支持用户使用http客户端向server发送json格式的数据请求,并返回json格式的响应。
提供丰富的工具类
sofa-pbrpc提供常用工具类给开发者,包括:
性能
测试环境
- cpu 16core
- memory 64G
- kernel 2.6.32_1-15-0-0
吞吐
延迟
支持团队
百度网页搜索部开源团队 opensearch@baidu.com
- 欢迎使用CSDN-markdown编辑器
- 欢迎使用CSDN-markdown编辑器
- 欢迎使用CSDN-markdown编辑器
- 欢迎使用CSDN-markdown编辑器
- 欢迎使用CSDN-markdown编辑器
- 欢迎使用CSDN-markdown编辑器
- 欢迎使用CSDN-markdown编辑器
- 欢迎使用CSDN-markdown编辑器
- 欢迎使用CSDN-markdown编辑器
- 欢迎使用CSDN-markdown编辑器
- 欢迎使用CSDN-markdown编辑器
- 欢迎使用CSDN-markdown编辑器
- 欢迎使用CSDN-markdown编辑器
- 欢迎使用CSDN-markdown编辑器
- 欢迎使用CSDN-markdown编辑器
- 欢迎使用CSDN-markdown编辑器
- 欢迎使用CSDN-markdown编辑器
- 欢迎使用CSDN-markdown编辑器
- Machine Learning week 3 quiz : Logistic Regression
- 网络文件系统nfs使用方法
- ^=
- 00 EditorOnlyPlayerSettings property iOS::ScriptingBackend not inititalized.
- 勾股定理一日一证连载118
- 欢迎使用CSDN-markdown编辑器
- UVA 11400 Lighting System Design 照明系统设计(DP)
- 微信小程序把玩(三十八)获取设备信息 API
- CVPR 2016-9-29
- 几何与力量的结合
- java日志管理
- 查找算法总结
- 4.5Bootstrap学习js插件篇之工具提示
- Medium 53题 Maximum Subarray