目录
本章主要是学习和使用本项目中所需使用到的一些框架。
brpc
RPC框架
RPC(Remote Procedure Call,远程过程调用)框架,是一种用于实现分布式系统中跨网络调用远程服务的工具。
它允许程序像调用本地函数一样调用远程服务器上的函数,隐藏了底层网络通信的复杂性。
举例:想要实现一个a + b的函数,我们只需写好函数头,然后在函数内部调用远程服务器上的a+b函数,远程服务器计算完成之后返还结果。
核心概念
客户端(Client) | 发起远程调用的程序。 |
服务端(Server) | 提供远程服务的程序。 |
存根(Stub) | 客户端代理,负责将调用请求打包并发送给服务端。 |
骨架(Skeleton) | 服务端代理,负责接收请求并调用实际的服务实现。 |
工作原理
调用 | 客户端通过存根发起远程调用。 |
序列化 | 存根将调用信息序列化为网络传输格式。 |
传输 | 序列化后的数据通过网络发送到服务端。 |
反序列化 | 服务端的骨架接收并反序列化数据。 |
执行 | 骨架调用本地服务实现。 |
返回 | 服务端将结果序列化后返回给客户端。 |
反序列化 | 客户端存根接收并反序列化结果,返回给调用者。 |
介绍
brpc是用C++编写的工业级RPC框架,常用于搜索、存储、机器学习、广告、推荐等高性能系统。
特点:
能搭建在一个端口支持多协议的服务,或访问各种服务。 |
Server能同步或异步处理请求。 |
Client支持同步、异步、半同步,或使用组合channels简化复杂的分库或并发访问。 |
通过http界面调试服务,使用cpu、heap、contention profilers。 |
获得更好的延时和吞吐。 |
把你组织中使用的协议快速地加入brpc,或定制各类组件,包括命名服务,负载均衡。 |
安装
先安装依赖:
sudo apt-get install
git g++ make libssl-dev libprotobuf-dev libprotoc-dev protobuf-compiler libleveldb-dev
通过github上的brpc源码进行安装。
brpc的github地址:https://github.com/apache/brpc.git
通过命令安装:
# 克隆远端仓库
git clone https://github.com/apache/brpc.git
# 进入工作目录
cd brpc/
# 创建build
mkdir build && cd build
# 使用cmake构建Makefile
cmake .. -DCMAKE_INSTALL_PREFIX=/usr && cmake --build . -j6
# make安装
make && sudo make install
头文件包含和编译时指明库
#include <brpc/channel.h>
#include <brpc/server.h>
#include <butil/logging.h>
-lbrpc -lssl -lleveldb -lcrypto -lprotobuf -lgflags
类与接口介绍
日志输出类与接口
本项目采用spdlog进行日志输出,这里只是想关闭brpc自带的日志输出系统。
/usr/include/butil/logging.h:
namespace logging {
// TODO(avi): do we want to do a unification of character types here?
#if defined(OS_WIN)
typedef wchar_t LogChar;
#else
typedef char LogChar;
#endif
// Where to record logging output? A flat file and/or system debug log
// via OutputDebugString.
enum LoggingDestination {
LOG_TO_NONE = 0,
LOG_TO_FILE = 1 << 0,
LOG_TO_SYSTEM_DEBUG_LOG = 1 << 1,
LOG_TO_ALL = LOG_TO_FILE | LOG_TO_SYSTEM_DEBUG_LOG,
// On Windows, use a file next to the exe; on POSIX platforms, where
// it may not even be possible to locate the executable on disk, use
// stderr.
#if defined(OS_WIN)
LOG_DEFAULT = LOG_TO_FILE,
#elif defined(OS_POSIX)
LOG_DEFAULT = LOG_TO_SYSTEM_DEBUG_LOG,
#endif
};
struct BUTIL_EXPORT LoggingSettings {
// The defaults values are:
//
// logging_dest: LOG_DEFAULT
// log_file: NULL
// lock_log: LOCK_LOG_FILE
// delete_old: APPEND_TO_OLD_LOG_FILE
LoggingSettings();
LoggingDestination logging_dest;
// The three settings below have an effect only when LOG_TO_FILE is
// set in |logging_dest|.
const LogChar* log_file;
LogLockingState lock_log;
OldFileDeletionState delete_old;
};
// This function may be called a second time to re-direct logging (e.g after
// loging in to a user partition), however it should never be called more than
// twice.
inline bool InitLogging(const LoggingSettings& settings) {
return BaseInitLoggingImpl(settings);
}
通过logging::LoggingDestination::LOG_TO_NONE + LoggingSettings::logging_dest + InitLogging来将日志的输出地设为0,即不输出。
#include <butil/logging.h>
int main(int argc, char *argv[])
{
logging::LoggingSettings settings;
settings.logging_dest = logging::LoggingDestination::LOG_TO_NONE;
logging::InitLogging(settings);
return 0;
}
protobuf类与接口
Closure类
/usr/include/google/protobuf/stubs/callback.h:
namespace google {
namespace protobuf {
class PROTOBUF_EXPORT Closure {
public:
Closure() {}
virtual ~Closure();
virtual void Run() = 0;
};
// See Closure.
inline Closure* NewCallback(void (*function)()) {
return new internal::FunctionClosure0(function, true);
}
}
}
Closure
类用于定义异步操作完成后的回调逻辑。它是一个抽象类,用户需要继承并实现Run()
方法,该方法在 RPC 调用完成时被调用。
主要功能:
-
回调机制:
Closure
允许用户在 RPC 调用完成后执行自定义逻辑。 -
资源管理:通过
NewCallback()
函数创建Closure
对象,自动管理其生命周期。
即:Closure类中的Run方法,是在客户端完成RPC调用之后的回调函数。
RpcController类
/usr/include/google/protobuf/service.h:
namespace google {
namespace protobuf {
class PROTOBUF_EXPORT RpcController {
// After a call has finished, returns true if the call failed. The possible
// reasons for failure depend on the RPC implementation. Failed() must not
// be called before a call has finished. If Failed() returns true, the
// contents of the response message are undefined.
virtual bool Failed() const = 0;
// If Failed() is true, returns a human-readable description of the error.
virtual std::string ErrorText() const = 0;
};
}
}
RpcController
类用于控制 RPC 调用的行为和状态,提供对调用过程的控制接口。
主要功能:
-
调用控制:支持取消、重置等操作。
-
状态查询:检查调用是否完成、是否失败等。
-
错误处理:获取错误信息和状态码。
常用方法:
-
Reset()
:重置控制器状态,用于复用。 -
Failed()
:检查调用是否失败。 -
ErrorText()
:获取错误信息。 -
SetFailed()
:手动标记调用为失败。 -
StartCancel()
:取消调用。
服务端类与接口
ServerOptions类
/usr/include/brpc/server.h:
namespace brpc{
struct ServerOptions {
// connections without data transmission for so many seconds will be closed
// Default: -1 (disabled)
int idle_timeout_sec
// Number of pthreads that server runs on. Notice that this is just a hint,
// you can't assume that the server uses exactly so many pthreads because
// pthread workers are shared by all servers and channels inside a
// process. And there're no "io-thread" and "worker-thread" anymore,
// brpc automatically schedules "io" and "worker" code for better
// parallelism and less context switches.
// If this option <= 0, number of pthread workers is not changed.
// Default: #cpu-cores
int num_threads;
};
// Represent server's ownership of services.
enum ServiceOwnership {
SERVER_OWNS_SERVICE, // 添加服务失败时, 服务器自动删除服务对象
SERVER_DOESNT_OWN_SERVICE // 添加服务失败时, 服务器不会删除服务对象
};
}
向 brpc 服务器添加服务,通常是指用户实现一个基于 Protobuf 定义的服务接口,并将其注册到 brpc 服务器中。这个过程确实需要用户重写服务函数,但不仅仅是简单的函数重写,而是需要遵循一定的规范和流程。
以下是向 brpc 服务器添加服务的详细步骤:
使用 Protobuf 定义服务接口。
实现服务接口中的虚函数(即重写服务函数)。
将服务实例注册到 brpc 服务器。
启动服务器并处理客户端请求。
Server类
namespace brpc{
class Server {
// Start on IP_ANY:port.
int Start(int port, const ServerOptions* opt);
// Stop accepting new connections and requests from existing connections.
// Returns 0 on success, -1 otherwi