目錄
brpc
RPC框架
核心概念
工作原理
介紹
安裝
頭文件包含和編譯時指明庫
類與接口介紹
日志輸出類與接口
protobuf類與接口
Closure類
RpcController類
服務端類與接口
ServerOptions類
Server類
ClosureGuard類
HttpHeader類
Controller類
客戶端類與接口
ChannelOptions類
Channel類
使用
同步調用
proto文件
server端
client端
Makefile
異步調用
client端
封裝channel
封裝思想(結合etcd服務發現模塊的回調函數)
ServiceChannel類
ServiceChannelManager類
代碼測試
main.proto
reg.cc
dis.cc
Makefile
測試結果
本章主要是學習和使用本項目中所需使用到的一些框架。
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_FILELoggingSettings();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-coresint 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