mrpc框架项目的AI总结
这份内容虽然技术细节丰富,但核心思想其实是理解一套完整的RPC框架的构建流程——从定义协议到网络传输再到业务调用。下面我会按照“从整体到细节”的方式,逐步拆解每一部分的内容,让你理解它的运行机制和设计思想。
一、整体架构透视
你所描述的是一个基于Protobuf的RPC框架,具有如下特征:
- 跨平台、跨语言:只需要定义一次
.proto
文件,生成不同语言的代码,实现互操作。 - 服务与调用流程整合:从定义协议、实现服务、注册、调用、网络传输,到服务发现(通过ZooKeeper)都完整呈现。
- 核心组件:包括整套代码结构的“协议层”、
Service
、Method
、Message
、网络通信(muduo库)以及注册/发现(ZooKeeper)等。
我会从这个架构的三大部分入手:
- 服务端注册和实现:如何定义、调用、注册、启动RPC服务
- 客户端调用流程:如何发起请求、网络传输、序列化、反序列化
- 底层网络通信实现:用socket、muduo封装请求/响应,保证数据完整性和交互一致性
二、架构层次分析
1. Protocol(协议定义)
- 使用
.proto
描述一个RPC服务(如登录、注册等) - 生成对应的代码(
.pb.h/.cc
),定义了请求、响应对象的结构 - 提供虚函数接口,让用户实现具体逻辑
这等于给系统定义了“契约”:服务名、方法名、参数、返回值一定要符合协议描述,否则通信会失败。
2. 代码生成层(依赖代码、服务逻辑)
- 继承自
google::protobuf::Service
的抽象类实例(如UserServiceRpc
) - 用户写实现类,重写虚函数(如
Login
、Hello
) - 利用虚函数,框架可以在网络级统一调用(比如,收到请求后,找到对应方法,调用虚函数)
重点:
- 设计了接口和调用的桥梁,让调用方(客户端)和实现层(业务逻辑)彻底解耦。
3. 网络通信层(基于muduo)
- 使用muduo框架做高性能网络通信
- 连接建立后,通过
OnMessage()
解析字节流 - 协议格式:定义RPC协议头(服务名、方法名、参数长度)+参数内容
- 网络收到数据后,反序列化,找到对应服务和方法,调用虚函数完成业务逻辑
4. 注册与发现(ZooKeeper)
- 服务提供方:注册自己的IP、端口,注册到ZooKeeper
- 调用方:通过调用ZooKeeper获取服务提供机器的地址,从而发起RPC请求
- 这样支持动态扩容/缩容,不用硬编码IP和端口。
三、详细流程拆解
我会从客户端调用、到服务端响应的完整流程讲起,确保每个环节都清晰。
【其实端:服务实现 -> 注册 -> 监听请求】
1. 定义协议(proto)
比如user.proto
的内容:
复制代码
service UserServiceRpc {rpc Login(LoginRequest) returns(LoginResponse);
}
message LoginRequest {bytes name=1;bytes pwd=2;
}
message LoginResponse {ResultCode result=1;bool success=2;
}
说明:
- 定义了服务接口和数据结构。
- 生成代码后,类
UserServiceRpc
的虚函数需要由用户实现。
2. 实现具体服务(“业务端”)
复制代码
class UserService : public fixbug::UserServiceRpc {
public:void Login(RpcController* controller,const LoginRequest* request,LoginResponse* response,Closure* done) override {// 处理具体业务(比如数据库验证等)response->set_success(true);// 设置返回状态done->Run(); // 通知框架请求已处理完毕}
};
3. 注册服务
复制代码
// 注册到RPC框架,由核心部调用
provider.NotifyService(new UserService());
// 启动RPC服务
provider.Run();
到此为止,服务端内容已经准备完毕——定义、实现、注册、监听。
【调用端:客户端发起请求】
4. 生成Stub
复制代码
// 生成Stub,绑定网络连接
fixbug::UserServiceRpc_Stub stub(new MrpcChannel()); // MrpcChannel负责网络传输
5. 调用RPC
复制代码
// 填写请求参数
LoginRequest request;
request.set_name("user");
request.set_pwd("pass");
LoginResponse response;
MrpcController controller;
stub.Login(&controller, &request, &response, nullptr); //相当于发起请求
// 处理返回结果
if(controller.Failed()){// 网络错误、超时等
} else {// 业务返回的响应bool success = response.success();
}
6. 连接底层:MrpcChannel
- 重写
CallMethod()
- 组成带有“服务名、方法名、参数”的字节流
- 根据ZooKeeper查找服务提供者的IP、端口
- 建立socket连接
- 通过网络发出字节流
- 阻塞等待响应,读取、反序列化
- 解析出结果,填充
response
- 调用
done->Run()
结束请求
四、源码详解:关键点“我理解的模型”
1. Service
与MethodDescriptor
Service
:虚拟的服务接口,包含虚函数CallMethod()
,通过请求调动对应的方法。MethodDescriptor
:描述单个RPC方法(名字、输入类型、输出类型、Streaming支持等)
【理解】:
这是告诉框架“我有这些方法”,运行时通过名字找到对应的Function。
2. Message
类
- 所有协议消息(请求、响应)都是Message的子类
- 提供序列化和反序列化接口(SerializeToString/ParseFromString)
- 方便在网络中传输
【理解】:
每个RPC参数和结果,本质都是一份统一格式的对象,可以序列化传输。
3. Stub
和Channel
Stub
:调用者的“接口代理”,封装了网络细节。Channel
:负责实际的网络传输,包含序列化、socket连接、发包、收包、反序列化。
【理解】:
调用stub.Login()
,最后会走到MrpcChannel::CallMethod()
,在此:
- 组装请求字节流(包括头信息、参数内容)
- 调用ZooKeeper获服用地址
- 连接服务器
- 发送请求
- 等待响应
- 反序列化
- 填充返回结果,调用
done->Run()
5. 核心网络协议格式
- 传输格式:
复制代码
[RPC header length][RPC header][参数内容]
RPC header
:包括服务名、方法名、参数长度,序列化的Protobuf结构参数内容
:请求对象序列化后的二进制
【理解】:
这是一个“消息前缀长度+内容”的设计思想,有利于拆包和粘包的处理。
6. ZooKeeper的作用
- 注册:服务端把自己的(IP、端口)注册到ZooKeeper路径(如
/service/method
) - 发现:客户端通过ZooKeeper接口查找对应服务、方法对应的IP、端口
- 这样,客户端不用硬编码地址,可以实现真正的“服务发现”
【理解】:
ZooKeeper负责存储“服务的动态信息”,确保可以在扩展时动态找到对应的节点。
五、总结与理解建议
这个统一框架设计的亮点:
- 定义清晰:协议层次(proto定义→代码→服务)
- 解耦强:协议、网络、业务逻辑层完全解耦
- 易扩展:通过注册、发现机制,支持集群和负载均衡
- 高性能:使用muduo库和异步回调机制
关键点理解:
Service
、MethodDescriptor
、Message
:描述RPC体系中的“组件”Stub
:调用入口Channel
:网络传输- 网络协议:长度|头信息|参数内容组成的请求包
- 注册流程:服务端注册、ZooKeeper存储
- 调用流程:客户端写请求→网络发→服务端解析→执行业务→返回响应