BRpc使用

一、基础概念

RPC(Remote Procedure Call)远程过程调⽤,简单来说就是客⼾端在不知道调⽤细节的情况下,调

⽤远程计算机上的某个功能就像调⽤本地功能⼀样,其主要⽬标就是让构建分布式计算(应⽤)更容

易,在提供强⼤的远程调⽤能⼒时不损失本地调⽤的语义简洁性。

框架 开发者 语言支持 序列化 http协议 文档 编译问题(ubuntu 22.04) 服务端推送 异步调用 流式传输(大块数据传输) 易用性
grpc google C++、Java、Python、Go pb 支持 文档较为完善,没有中文档 主要是下载submodule的问题,没有vpn 不支持 1.异步客户端需要用户自己创建消费线程,使用起来较为麻烦 2.支持异步服务器 支持(接口简单易用) 1.简单易用 2.支持跨语言、跨平台
brpc baidu C++ pb 支持 文档较为完善,有中文文档 编译基本没有问题 支持,但是支持的不好,是通过一次长的RPC调用实现的 1.通过回调函数支持客户端异步调用 支持(接口稍微比grpc原生) 1.提供简洁的API和友好的使用文档,易于上手 2.在sofa-pbrpc基础上加了一些封装,比如资源管理等,更易用
srpc sogou C++ pb、Thrift 支持 文档略显简单,没有独立网站、都托管在github 编译基本没有问题 不支持 1.支持异步客户端 2.通过workflow支持异步服务器 不支持 专注于异步编程,性能较高,用起来更复杂一些
sofa-pbrpc baidu C++、Java pb 支持 官方文档较少 编译存在问题依赖的库版本都比较老 不支持 1.通过回调函数客户端异步调用 不支持 1.轻量化 2.接口简单,容易使用

brpc 框架介绍

brpc是用C++语言编写的工业级RPC框架,常用于搜索、存储、机器学习、广告、推荐等高性能系统。

核心能力

你可以使用它实现以下功能:

  1. 搭建单端口多协议服务,同时可访问各类异构服务
  • restful http/https、h2/gRPC:brpc内置HTTP实现,使用比libcurl更便捷;支持其他语言通过HTTP/h2+JSON调用基于protobuf定义的协议
  • redis、memcached:客户端线程安全,API比官方client更易用
  • rtmp/flv/hls:可快速搭建流媒体服务
  • thrift:线程安全客户端,使用体验优于官方client
  • 百度系列私有协议:baidu_std、streaming_rpc、hulu_pbrpc、sofa_pbrpc、nova_pbrpc、public_pbrpc、ubrpc,以及所有基于nshead封装的协议
  • 分布式高可用集群:配套开源braft,基于工业级RAFT算法实现高可靠分布式系统
  1. 服务端请求处理

    Server 支持同步、异步两种模式处理客户端请求

  2. 多样化客户端调用方式

    Client 原生支持同步、异步、半同步调用;支持组合Channels,简化分库、批量并发访问等复杂业务场景

  3. 内置可视化调试与性能剖析

    提供HTTP可视化调试界面,集成CPU、堆内存、锁竞争性能分析工具,方便定位性能问题

  4. 高性能优势

    具备更低请求延迟、更高系统吞吐量

  5. 高度自定义扩展能力

  • 快速接入企业内部自定义私有协议
  • 可定制各类核心组件:
    • 命名服务:DNS、ZooKeeper、etcd等
    • 负载均衡策略:轮询、随机、一致性哈希等

二、类与接口介绍

2.1 ⽇志输出类与接口

包含头⽂件: #include <butil/logging.h>

brpc库内有⼈家⾃⼰的⽇志输出模块(⽆法替换,除⾮修改库内源码中所有的⽇志输出操作后重新编

译库进⾏安装),这⾥我们主要是了解他的⽇志级别,将不需要的⽇志输出给禁⽤掉,避免其运⾏时

的⼤量⽇志输出影响我们的视线。

cpp 复制代码
namespace logging {
	enum LoggingDestination {
		LOG_TO_NONE = 0
	};
	struct BUTIL_EXPORT LoggingSettings {
		LoggingSettings();
		LoggingDestination logging_dest;
	};
	bool InitLogging(const LoggingSettings& settings);
}

2.2 服务端类与接口

cpp 复制代码
namespace brpc {
	struct ServerOptions {
		//⽆数据传输,则指定时间后关闭连接
		int idle_timeout_sec; // Default: -1 (disabled)
		// 设置c线程池数量,默认cpu数量
		int num_threads; // Default: #cpu-cores
		//....
	}
	enum ServiceOwnership {
		//添加服务失败时,服务器将负责删除服务对象
		SERVER_OWNS_SERVICE,
		//添加服务失败时,服务器也不会删除服务对象
		SERVER_DOESNT_OWN_SERVICE
	};
	class Server {
		// 添加服务 
		// google::protobuf::Service* service告诉服务器请求用哪个函数进行业务处理
		int AddService(google::protobuf::Service* service,
		ServiceOwnership ownership);
		int Start(int port, const ServerOptions* opt);
		int Stop(int closewait_ms/*not used anymore*/);
		int Join();
		//休眠直到ctrl+c按下,或者stop和join服务器
		void RunUntilAskedToQuit();
	}
	class ClosureGuard {
		explicit ClosureGuard(google::protobuf::Closure* done);
		~ClosureGuard() { if (_done) _done->Run(); }
	}
}
  • 实际使用
proto 复制代码
syntax = "proto3";
package cal;
// 开启通用服务
option cc_generic_services = true;

message AddReq
{
    int32 num1 = 1;
    int32 num2 = 2;
}
message AddResp
{
    int32 result = 1;
}
// 加法服务
service CalService
{
    rpc Add(AddReq) returns (AddResp);
}
  • 生成的处理函数
cpp 复制代码
  virtual void Add(::PROTOBUF_NAMESPACE_ID::RpcController* controller,
                       const ::cal::AddReq* request,
                       ::cal::AddResp* response,
                       ::google::protobuf::Closure* done);
  • Controller 类

对于服务端,主要用于获取HTTP请求信息,及设置HTTP响应信息

cpp 复制代码
class Controller : public google::protobuf::RpcController {
	// 设置超时时间
	void set_timeout_ms(int64_t timeout_ms);
	// 最大重试次数
	void set_max_retry(int max_retry);
	void Reset();
	google::protobuf::Message* response();
	// HTTP相关
	HttpHeader& http_response();
	butil::IOBuf& response_attachment();
	HttpHeader& http_request();
	butil::IOBuf& request_attachment();
	// 请求失败及错误原因
	bool Failed();
	std::string ErrorText();
	using AfterRpcRespFnType = std::function<
	void(Controller* cntl,
	const google::protobuf::Message* req,
	const google::protobuf::Message* res)>;
	void set_after_rpc_resp_fn(AfterRpcRespFnType&& fn)
}
  • inline Closure* NewCallback(void (*function)());函数

很多rpc框架中都支持异步操作,业务处理过程,不一定非要放到这个Add函数内进行,本次请求的结束与否,不由Add函数生命周期决定,当执行done->Run()的时候表示处理完毕

通过一下类实现RAII特性

cpp 复制代码
class ClosureGuard {
explicit ClosureGuard(google::protobuf::Closure* done);
~ClosureGuard() { if (_done) _done->Run(); }
}

2.3简易服务器搭建

cpp 复制代码
#include <brpc/server.h>
#include <butil/logging.h>
#include "cal.pb.h"

class CalServiceImpl : public cal::CalService
{
public:
    CalServiceImpl(){}
    ~CalServiceImpl(){}
    virtual void Add(::google::protobuf::RpcController* controller,
                    const ::cal::AddReq* request,
                    ::cal::AddResp* response,
                    ::google::protobuf::Closure* done)
        {
            brpc::ClosureGuard guard(done); // 确保done在函数结束时被调用
            int result = request->num1() + request->num2();
            response->set_result(result);
        }
        // 异步服务端修改
        /*{

            std::thread thread([=](){
                // 异步处理 -- 核心思想,将done->Run()放到线程中执行
                brpc::ClosureGuard guard(done); 
                int result = request->num1() + request->num2();
                response->set_result(result);
                std::this_thread::sleep_for(std::chrono::seconds(3));
            });
            thread.detach();// 分离线程,将线程资源释放给系统
            std::cout << "------------------------------" << std::endl;
        }*/
};


int main(int argc, char* argv[])
{
    // 1. 实例化计算服务对象
    CalServiceImpl cal_service;
    // 2. 定义服务器配置对象
    brpc::ServerOptions options;
    options.idle_timeout_sec = -1;
    // 实例化服务器对象
    brpc::Server server;
    // 注册服务
    int ret = server.AddService(&cal_service, brpc::SERVER_OWNS_SERVICE);
    if(ret == -1)
    {
        std::cerr << "AddService failed, ret = " << ret << std::endl;
        return -1;
    }
    // 启动服务器
    ret = server.Start(9000, &options);
    if(ret == -1)
    {
        std::cerr << "Start failed, ret = " << ret << std::endl;
        return -1;
    }
    // 等待服务器退出
    server.RunUntilAskedToQuit();
    return 0;
}

2.4客⼾端类与接口

CaService Stub:用于客户端进行rpc远程调用 CalService Stub(:google:protobuf:RpcChannel* channel)

class Channel { int Init( const chart server addr and_port, const ChannelOptionst options); )

cpp 复制代码
struct ChannelOptions {
	//请求连接超时时间
	int32_t connect_timeout_ms;// Default: 200 (milliseconds)
	//rpc请求超时时间
	int32_t timeout_ms;// Default: 500 (milliseconds)
	//最⼤重试次数
	int max_retry;// Default: 3
	//序列化协议类型 options.protocol = "baidu_std";
	AdaptiveProtocolType protocol;
	//....
}
class Channel : public ChannelBase {
	//初始化接⼝,成功返回0;
	int Init(
	const char* server_addr_and_port, //192.168.xx.xx:9000
	const ChannelOptions* options);
	void CallMethod(const google::protobuf::MethodDescriptor* method,
	google::protobuf::RpcController* controller,
	const google::protobuf::Message* request,
	google::protobuf::Message* response,
	google::protobuf::Closure* done);
};
inline ::google::protobuf::Closure* NewCallback(void (*function)());
  • 客户端示例代码
cpp 复制代码
#include <brpc/server.h>
#include <butil/logging.h>
#include "cal.pb.h"

class CalServiceImpl : public cal::CalService
{
public:
    CalServiceImpl(){}
    ~CalServiceImpl(){}
    virtual void Add(::google::protobuf::RpcController* controller,
                    const ::cal::AddReq* request,
                    ::cal::AddResp* response,
                    ::google::protobuf::Closure* done)
        {
            brpc::ClosureGuard guard(done); // 确保done在函数结束时被调用
            int result = request->num1() + request->num2();
            response->set_result(result);
        }
};


int main(int argc, char* argv[])
{
    // 1. 实例化计算服务对象
    CalServiceImpl cal_service;
    // 2. 定义服务器配置对象
    brpc::ServerOptions options;
    options.idle_timeout_sec = -1;
    // 实例化服务器对象
    brpc::Server server;
    // 注册服务
    int ret = server.AddService(&cal_service, brpc::SERVER_OWNS_SERVICE);
    if(ret == -1)
    {
        std::cerr << "AddService failed, ret = " << ret << std::endl;
        return -1;
    }
    // 启动服务器
    ret = server.Start(9000, &options);
    if(ret == -1)
    {
        std::cerr << "Start failed, ret = " << ret << std::endl;
        return -1;
    }
    // 等待服务器退出
    server.RunUntilAskedToQuit();
    return 0;
}
  • 异步客户端
cpp 复制代码
#include <brpc/channel.h>
#include <butil/logging.h>
#include "cal.pb.h"

void Callback(brpc::Controller* cntl, cal::AddReq* request, cal::AddResp* response)
{
    std::unique_ptr<brpc::Controller> cntl_ptr(cntl);
    std::unique_ptr<cal::AddReq> request_ptr(request);
    std::unique_ptr<cal::AddResp> response_ptr(response);
    if (cntl_ptr->Failed())
    {
        std::cout << "Add failed: " << cntl_ptr->ErrorText() << std::endl;
        return;
    }
    std::cout << "Add success: " << response_ptr->result() << std::endl;
}

// 异步调用
int main(int argc, char* argv[])
{
    // 实例化ChannelOptions对象
    brpc::ChannelOptions options;
    options.protocol = "baidu_std";
    // 1. 实例化Channel对象
    brpc::Channel channel;
    channel.Init("192.168.220.128:9000", &options);

    // 实例化CalService对象 -- 客户端调用服务端的方法
    cal::CalService_Stub stub(&channel);

    brpc::Controller *cntl = new brpc::Controller;
    cal::AddReq *request = new cal::AddReq;
    cal::AddResp *response = new cal::AddResp;
    request->set_num1(1);
    request->set_num2(2);
    // 异步调用 -- 响应处理函数
    // 不支持lambda表达式,只能是普通函数
    google::protobuf::Closure *callback = brpc::NewCallback(Callback, cntl, request, response);
    
    stub.Add(cntl, request, response, callback);
    std::cout << "-------------------------------" << std::endl;

    getchar();
    return 0;
}
相关推荐
-森屿安年-2 小时前
63. 不同路径 II
c++·算法·动态规划
chase_my_dream2 小时前
Cartographer详细讲解
c++·人工智能·自动驾驶
森G2 小时前
75、服务器源码解析---------云视频服务项目
linux·服务器·网络·c++·qt
碧海蓝天20222 小时前
C++法则24:在标准 C++ 中,没有任何可移植的方式判断指针 T* pt 指向的内存位置是否已经 构造了对象,程序员必须手动跟踪哪些元素已构造。
java·开发语言·c++
charlie1145141912 小时前
现代C++指南:Lambda,让我们用另一种方式持有函数
开发语言·c++
森G2 小时前
77、线程池原理和实现------服务器源码解析----云视频服务项目
服务器·c++·qt
.千余3 小时前
【C++】模板进阶全解:非类型参数|全特化|偏特化|分离编译完全指南
开发语言·c++·笔记·学习·其他
代码改善世界3 小时前
【C++进阶】C++11:列表初始化、右值引用与移动语义、完美转发全解析
java·开发语言·c++
牛油果子哥q3 小时前
并查集(DSU)超精讲,路径压缩、按秩合并、万能模板、连通性判定、最小生成树与刷题实战全解
数据结构·c++·最小生成树·并查集