Skip to content

miniRPC —— 从零到一实现一个 Go RPC 框架

项目目标

使用 Go 语言从零实现一个名为 miniRPC 的轻量级 RPC 框架,以渐进式、模块化的方式逐章构建,最终形成一个具备生产参考价值的完整框架。

总体要求

  • Go 版本:1.21+,使用 Go Modules 管理依赖
  • 项目根目录:/data/workspace/learnNote/miniRPC
  • 每个章节对应一个独立可运行的子目录(如 day1-codec/day2-server/),同时在项目根目录维护一个持续演进的 minirpc/ 核心库
  • 代码风格遵循 Go 官方规范,通过 go vetgolint 检查
  • 每章需包含:可运行的示例代码(example/)、单元测试(覆盖率 ≥ 80%)、README.md 说明文档

章节规划

Day 1 — 消息编解码(Codec)

目标: 设计 RPC 消息协议格式,实现序列化/反序列化层

  • 定义消息结构:Header(MagicNumber、ServiceMethod、Seq、Error)+ Body
  • 实现 Codec 接口,提供 GobCodecJsonCodec 两种实现
  • 支持通过 Option 在连接握手阶段协商编解码方式
  • 交付物: codec 包、编解码 benchmark 测试、协议格式说明文档

Day 2 — 服务端基础架构(Server)

目标: 实现高并发 TCP 服务端,能接收并处理 RPC 请求

  • 基于 net.Listener 实现连接监听与接入
  • 实现请求的读取(readRequest)、处理(handleRequest)、响应(sendResponse)完整生命周期
  • 使用 sync.Mutex 保证响应的有序发送;使用 sync.WaitGroup 实现优雅等待
  • 支持单连接上的并发请求处理
  • 交付物: server 包、集成测试(模拟多并发请求)

Day 3 — 客户端与调用封装(Client)

目标: 实现支持异步和同步调用的 RPC 客户端

  • 设计 Call 结构体,封装一次 RPC 调用的完整生命周期(ServiceMethod、Args、Reply、Error、Done channel)
  • 实现 Client.Go()(异步)和 Client.Call()(同步)两种调用方式
  • 客户端并发安全:使用 pending map 管理进行中的请求,支持多 goroutine 共享同一连接
  • 连接异常处理:服务端断开时,自动终止所有 pending 请求
  • 交付物: client 包、异步/同步调用示例、错误场景测试

Day 4 — 服务注册与反射调用(Service)

目标: 实现服务的自动注册和基于反射的方法调用

  • 定义 RPC 方法签名规范:func (t *T) MethodName(args ArgType, reply *ReplyType) error
  • 使用 reflect 包实现服务方法的自动发现与注册
  • 参数/返回值类型校验,自动创建入参和出参实例
  • 将 service 层集成到 Server 中,实现 ServiceMethod 格式:Service.Method
  • 交付物: service 包、反射调用的 benchmark、端到端调用示例

Day 5 — HTTP 支持与调试页面

目标: 支持通过 HTTP 协议承载 RPC 调用,并提供 Web 调试界面

  • 实现 HTTP CONNECT 方法进行协议切换(Hijack),复用已有 TCP 处理逻辑
  • 客户端支持通过 HTTP 拨号连接 RPC 服务
  • 提供 /debug/rpc 页面,展示已注册服务及调用统计信息
  • 交付物: HTTP 传输层代码、调试页面模板、HTTP 连接测试

Day 6 — 负载均衡与服务发现(Discovery)

目标: 实现客户端侧的服务发现与负载均衡机制

  • 定义 Discovery 接口,实现 MultiServerDiscovery(手动多节点列表)
  • 实现 XClient 封装,支持多节点调用
  • 负载均衡策略:Random(随机)、RoundRobin(轮询),可扩展
  • 提供 Broadcast 模式:向所有节点广播请求,任一出错即返回错误,全部成功才成功
  • 交付物: discovery + xclient 包、多节点调用示例、负载均衡策略测试

Day 7 — 超时与容错机制(Timeout)

目标: 在框架各关键环节引入超时控制,提升健壮性

  • 连接超时:客户端拨号超时控制(net.DialTimeout
  • 调用超时:Client.Call 支持 context.Context 传入,通过 select + time.After 实现
  • 服务端处理超时:handleRequest 增加超时控制,防止慢请求阻塞
  • 优雅关闭:服务端支持信号监听,等待已有请求处理完毕后关闭
  • 交付物: 超时控制集成代码、超时场景测试用例(连接超时/处理超时/调用超时)

Day 8 — 中间件与拦截器(Middleware)(可选进阶)

目标: 提供请求处理管线,支持日志、鉴权、限流等横切关注点

  • 定义 Interceptor 接口(Unary 拦截器)
  • 支持服务端和客户端分别注册拦截器链
  • 内置实现:AccessLog 日志拦截器、Recovery panic 恢复拦截器
  • 交付物: middleware 包、拦截器链测试、自定义拦截器示例

每章交付规范

dayN-xxx/
├── README.md           # 本章学习目标、核心概念、架构图、关键代码讲解
├── doc/
│   └── design.md       # 技术设计文档:接口定义、流程图、设计决策与取舍
├── example/
│   ├── server/
│   │   └── main.go     # 可独立运行的服务端示例
│   └── client/
│       └── main.go     # 可独立运行的客户端示例
├── <package>/
│   ├── *.go            # 核心实现代码
│   └── *_test.go       # 单元测试(覆盖率 ≥ 80%)
└── go.mod

文档要求

  • README.md: 用通俗的语言解释本章实现了什么、为什么这样设计、如何运行示例
  • design.md: 包含接口设计(Go interface 定义)、核心流程时序图(可用 Mermaid)、与上一章的差异说明、关键设计决策的 trade-off 分析
  • 所有文档使用中文编写

约束与风格

  • 不使用任何第三方 RPC 框架(如 gRPC、rpcx),可使用标准库和基础工具库
  • 优先可读性,代码中对关键设计决策添加注释说明(不要冗余注释)
  • 每章代码可独立编译运行,不强依赖后续章节
  • 变量/函数命名遵循 Go 惯例,包名简短有意义