Skip to content

miniRPC 整体架构设计

1. 架构总览

miniRPC 采用分层架构设计,自底向上分为四个层次:

┌─────────────────────────────────────────────────────────┐
│                    应用层 (Application)                    │
│            用户定义的 Service 结构体与方法                    │
├─────────────────────────────────────────────────────────┤
│                   框架层 (Framework)                       │
│  ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌────────────┐  │
│  │  Server   │ │  Client  │ │ XClient  │ │ Middleware │  │
│  │ 服务注册  │ │ 同步/异步 │ │ 服务发现  │ │  拦截器链   │  │
│  │ 请求分发  │ │ 连接管理  │ │ 负载均衡  │ │  日志/恢复  │  │
│  └──────────┘ └──────────┘ └──────────┘ └────────────┘  │
├─────────────────────────────────────────────────────────┤
│                   协议层 (Protocol)                        │
│  ┌──────────────────┐  ┌───────────────────────────┐     │
│  │  Option 握手协商   │  │    Codec 编解码接口        │     │
│  │  MagicNumber 校验  │  │  Gob │ Json │ Protobuf   │     │
│  └──────────────────┘  └───────────────────────────┘     │
├─────────────────────────────────────────────────────────┤
│                   传输层 (Transport)                       │
│            TCP 长连接  │  HTTP CONNECT 协议切换             │
└─────────────────────────────────────────────────────────┘

2. 核心组件关系

3. 请求生命周期

一次完整的 RPC 调用经历以下阶段:

4. 模块依赖图

                 ┌──────────────┐
                 │  middleware/  │
                 │  拦截器框架    │
                 └──────────────┘
                        │ (可选依赖)
    ┌───────────┐  ┌────┴─────┐  ┌──────────────┐
    │  xclient/ │──│  Client  │  │    Server     │
    │  服务发现  │  │  客户端   │  │    服务端     │
    │  负载均衡  │  └────┬─────┘  └──────┬───────┘
    └───────────┘       │               │
                   ┌────┴───────────────┴────┐
                   │      service.go          │
                   │   反射注册 & 方法调用      │
                   └────────────┬─────────────┘

                   ┌────────────┴─────────────┐
                   │        codec/             │
                   │  Gob │ Json │ Protobuf    │
                   └──────────────────────────┘

5. 关键设计决策

5.1 单连接多路复用

miniRPC 在单个 TCP 连接上支持多个并发 RPC 调用。通过 Seq(序列号)匹配请求和响应,避免为每次调用建立新连接。

优点:减少连接数,降低系统资源占用 代价:需要 pending map 管理状态,实现复杂度增加

5.2 Codec 可插拔

通过 Codec 接口和 NewCodecFuncMap 工厂注册表,编解码实现完全可插拔。新增编解码只需:

  1. 实现 Codec 接口
  2. init() 中注册到 NewCodecFuncMap

5.3 Option 握手

连接建立后,客户端先发送 JSON 编码的 Option。这一设计使得:

  • 编解码方式可协商(不硬编码)
  • 超时参数可按连接定制
  • 扩展新字段向后兼容(JSON 忽略未知字段)

5.4 反射调用 vs 代码生成

miniRPC 使用运行时反射发现和调用方法,而非 gRPC 式的代码生成。

维度反射 (miniRPC)代码生成 (gRPC)
开发体验无需 .proto + protoc需要工具链
类型安全运行时检查编译时检查
性能反射有开销零额外开销
跨语言仅 Go多语言

miniRPC 选择反射是为了简化开发流程,适合学习和中小规模场景。

5.5 超时三层防护

连接超时 (ConnectTimeout)
  └─ 防止 TCP 握手/协议协商过慢
调用超时 (context.Context)
  └─ 防止单次 RPC 等待过长(客户端控制)
处理超时 (HandleTimeout)
  └─ 防止服务端 handler 执行过久(服务端控制)

三层超时相互独立,提供完整的端到端超时保护。

6. 扩展点

扩展点接口/机制示例
编解码Codec 接口添加 MsgPack、Thrift 编码
服务发现Discovery 接口接入 etcd、Consul、ZooKeeper
负载均衡SelectMode 枚举添加一致性哈希、加权轮询
中间件ServerInterceptor / ClientInterceptor添加鉴权、限流、链路追踪
传输协议Dial / Accept添加 Unix Socket、QUIC

7. 线程模型

Server 端:
  main goroutine → Accept 循环
    └─ 每个连接: 1 个 serveCodec goroutine (串行读请求)
        └─ 每个请求: 1 个 handleRequest goroutine (并行处理)

Client 端:
  main goroutine → 发送请求 (send)
  background goroutine → 接收响应 (receive)

这种「读串行 + 处理并行 + 写加锁」的模型在保证正确性的同时最大化了并发度。