KVstorageBaseRaft-cpp 項目 RPC 模塊源碼學習
。
一、項目簡介
KVstorageBaseRaft-cpp 是一個基于 Raft 一致性算法實現的分布式 KV 存儲系統,采用 C++ 開發。項目的核心目標是幫助開發者理解 Raft 原理和分布式 KV 存儲的基本實現。RPC 模塊是分布式系統通信的關鍵基礎設施,負責節點間、客戶端與服務端之間的遠程過程調用。
二、RPC 模塊結構總覽
源碼主要位于 src/rpc/
目錄,包含如下關鍵文件:
mprpcchannel.h/cpp
:RPC 客戶端通道,負責序列化、發送請求、接收響應。mprpccontroller.h/cpp
:RPC 調用控制器,負責錯誤狀態管理。mprpcconfig.h/cpp
:RPC 配置加載,負責讀取 ip、端口等配置信息。rpcprovider.h/cpp
:RPC 服務端,負責服務注冊、請求分發和實際業務調用。rpcheader.proto
:RPC 協議頭部的 protobuf 定義。rpcheader.pb.h/cpp
:由 proto 自動生成的協議頭部 C++ 代碼。
三、核心源碼解讀
1. RPC 協議頭部定義
rpcheader.proto
內容如下:
syntax = "proto3";
package RPC;message RpcHeader {bytes service_name = 1;bytes method_name = 2;uint32 args_size = 3;
}
- 該消息定義了每次 RPC 調用的服務名、方法名和參數長度,便于服務端正確分發請求。
2. RPC 客戶端通道(mprpcchannel)
主要職責
- 負責將本地的 RPC 方法調用序列化為網絡數據包,發送到遠程服務端,并接收響應。
- 自動處理連接失敗時的重連與重試。
關鍵流程
- 獲取服務名和方法名
通過MethodDescriptor
自動獲取,便于通用化。 - 參數序列化
將請求參數序列化為字符串,記錄長度。 - 構造并序列化 RpcHeader
組裝服務名、方法名、參數長度,序列化為二進制。 - 數據打包
先寫入 header 長度(變長編碼),再寫入 header 內容,最后拼接參數內容。 - 發送與重連
發送失敗自動重連,保證健壯性。 - 接收與反序列化響應
用ParseFromArray
反序列化,避免字符串截斷 bug。
代碼片段舉例
// 1. 獲取服務名和方法名
const google::protobuf::ServiceDescriptor* sd = method->service();
std::string service_name = sd->name();
std::string method_name = method->name();// 2. 參數序列化
uint32_t args_size{};
std::string args_str;
if (request->SerializeToString(&args_str)) {args_size = args_str.size();
} else {controller->SetFailed("serialize request error!");return;
}// 3. 構造 RpcHeader
RPC::RpcHeader rpcHeader;
rpcHeader.set_service_name(service_name);
rpcHeader.set_method_name(method_name);
rpcHeader.set_args_size(args_size);// 4. 數據打包
std::string send_rpc_str;
{google::protobuf::io::StringOutputStream string_output(&send_rpc_str);google::protobuf::io::CodedOutputStream coded_output(&string_output);coded_output.WriteVarint32(static_cast<uint32_t>(rpc_header_str.size()));coded_output.WriteString(rpc_header_str);
}
send_rpc_str += args_str;// 5. 發送與重連
while (-1 == send(m_clientFd, send_rpc_str.c_str(), send_rpc_str.size(), 0)) {// ...重連邏輯...
}// 6. 接收與反序列化
if (!response->ParseFromArray(recv_buf, recv_size)) {controller->SetFailed("parse error!");return;
}
3. RPC 控制器(mprpccontroller)
- 負責記錄本次 RPC 調用的失敗狀態和錯誤信息,便于上層業務判斷和處理。
- 代碼簡潔,主要實現了
SetFailed
、Failed
、ErrorText
等接口。
4. RPC 服務端(rpcprovider)
- 負責服務注冊、請求分發和實際業務調用。
- 建議結合頭文件和實現文件一起閱讀,理解服務端如何根據收到的 RpcHeader 分發到具體的服務和方法。
5. 配置加載(mprpcconfig)
- 負責從配置文件讀取 ip、端口等信息,便于靈活部署和管理。