Skip to content

miniRPC 技术调研报告

1. RPC 框架全景

1.1 主流 RPC 框架对比

框架语言IDL序列化传输协议服务发现生态
gRPC多语言ProtobufProtobufHTTP/2插件式最完善
Apache Thrift多语言Thrift IDL多种TCP/HTTP无内置成熟
DubboJava/Go可选多种TCP/HTTP内置阿里系
rpcxGo无需多种TCP/QUIC内置Go 生态
net/rpcGo无需GobTCP/HTTP标准库
miniRPCGo无需Gob/Json/PBTCP/HTTP内置学习项目

1.2 核心设计维度

一个 RPC 框架的核心设计涉及以下维度:

RPC 框架
├── 序列化协议 ─── 如何编码数据?
├── 传输协议 ───── 如何传输数据?
├── 服务描述 ───── 如何定义接口?
├── 服务发现 ───── 如何找到服务?
├── 负载均衡 ───── 如何分配请求?
├── 容错机制 ───── 如何处理故障?
└── 可观测性 ───── 如何监控运行?

2. 序列化协议调研

2.1 候选方案对比

协议格式速度体积跨语言Schema可读性
JSON文本通用无需
Protobuf二进制通用.proto
Gob二进制仅 Go无需
MessagePack二进制通用无需
FlatBuffers二进制最快最小通用.fbs
Thrift Binary二进制通用.thrift

2.2 miniRPC Benchmark 实测数据

在 AMD EPYC 7K83 上的实测结果:

Codec吞吐 (ops/s)延迟 (ns/op)内存 (B/op)分配次数
Gob~653K1907161
Json~727K1747161
Protobuf~215K5107964

注:Protobuf 的延迟较高是因为使用了长度前缀帧 + JSON 编码 Header 的混合方案。 在纯 Body 编解码上,Protobuf 的序列化效率实际上优于 JSON。 对于大体积消息和跨语言场景,Protobuf 的优势会更加明显。

2.3 miniRPC 的选择

miniRPC 提供三种编解码,适用于不同场景:

Codec适用场景
GobCodecGo-to-Go 通信,开发调试阶段,追求极致性能
JsonCodec跨语言互通,需要可读性,调试排查
ProtobufCodec跨语言生产环境,消息体积敏感,有 Schema 管理需求

3. 传输协议调研

3.1 候选方案对比

协议特性优点缺点
TCP长连接、全双工低延迟、高吞吐无法穿透代理
HTTP/1.1请求-响应通用、可穿透代理队头阻塞、头部开销
HTTP/2多路复用、头部压缩gRPC 首选实现复杂
QUICUDP 上的可靠传输0-RTT、无队头阻塞新协议、NAT 穿越
Unix Socket本地进程间零网络开销仅限本机

3.2 miniRPC 的选择

miniRPC 采用 TCP 长连接 作为主传输,同时支持 HTTP CONNECT 协议切换:

  • TCP 直连:最低延迟,适合内网微服务
  • HTTP CONNECT:复用 HTTP 基础设施(反向代理、LB),然后切换到 TCP 长连接

选择理由:TCP 实现简单且性能最优;HTTP CONNECT 提供部署灵活性。

4. 服务发现调研

4.1 候选方案对比

方案一致性可用性复杂度代表
硬编码--最低配置文件
DNS最终一致DNS SRV
ZooKeeper强一致 (CP)Dubbo 默认
etcd强一致 (CP)Kubernetes
ConsulCP + AP 可选HashiCorp
Eureka最终一致 (AP)最高Spring Cloud
NacosCP + AP 可选阿里巴巴

4.2 miniRPC 的选择

miniRPC 通过 Discovery 接口抽象服务发现,当前内置 MultiServerDiscovery(静态列表)。

接口设计使得接入任何注册中心只需实现 4 个方法:

go
type Discovery interface {
    Refresh() error
    Update(servers []string) error
    Get(mode SelectMode) (string, error)
    GetAll() ([]string, error)
}

扩展示例:

go
type EtcdDiscovery struct {
    client  *clientv3.Client
    servers []string
    // ...
}

func (d *EtcdDiscovery) Refresh() error {
    // Watch etcd key prefix, update servers
}

5. 负载均衡调研

5.1 策略对比

策略原理优点缺点适用场景
随机rand 选择实现简单短期不均匀无状态、节点同质
轮询顺序分配绝对均匀不感知负载请求耗时均匀
加权轮询按权重分配适应异构节点需配置权重节点性能不同
最少连接选连接数最少自适应需维护计数长连接场景
一致性哈希哈希映射缓存亲和实现复杂有状态服务
P2C随机两选一低开销、自适应略有偏差大规模集群

5.2 miniRPC 的选择

miniRPC 内置 Random 和 RoundRobin,通过 SelectMode 枚举扩展:

go
const (
    RandomSelect     SelectMode = iota
    RoundRobinSelect
    // 可扩展:
    // WeightedRoundRobinSelect
    // ConsistentHashSelect
    // LeastConnectionSelect
)

6. 容错机制调研

6.1 常见策略

策略说明miniRPC 实现
超时控制限制等待时间✅ 三层超时
重试失败后重试❌ 可通过拦截器扩展
熔断错误率过高时快速失败❌ 可通过拦截器扩展
限流控制请求速率❌ 可通过拦截器扩展
降级返回兜底结果❌ 应用层实现
Failover切换到其他节点⚠️ XClient 部分支持

6.2 miniRPC 超时三层防护

┌─────────────────────────────────────────────┐
│ ConnectTimeout (客户端)                       │
│  └─ net.DialTimeout: TCP 握手 + 协议协商     │
├─────────────────────────────────────────────┤
│ Context Timeout (客户端)                      │
│  └─ select { ctx.Done / call.Done }          │
├─────────────────────────────────────────────┤
│ HandleTimeout (服务端)                        │
│  └─ select { time.After / called }           │
└─────────────────────────────────────────────┘

7. 可观测性调研

7.1 三大支柱

维度说明miniRPC 实现
日志 (Logging)请求级别的文本记录✅ AccessLog 拦截器
指标 (Metrics)聚合的数值统计⚠️ methodType.numCalls 基础计数
链路追踪 (Tracing)跨服务调用链❌ 可通过 context + 拦截器扩展

7.2 调试页面

miniRPC 提供 /debug/minirpc 页面,展示:

  • 已注册服务列表
  • 每个方法的参数类型
  • 累计调用次数

8. miniRPC 与 gRPC 的差异总结

维度miniRPCgRPC
定位学习项目生产级框架
IDL无需(反射)必须(.proto)
序列化Gob/Json/Protobuf 可选仅 Protobuf
传输TCP + HTTP CONNECTHTTP/2
流式调用不支持Unary + Server/Client/Bidi Stream
代码生成protoc-gen-go
拦截器基础支持完善(Unary + Stream)
服务发现内置简单实现需要 resolver 插件
连接管理单连接 + pending mapHTTP/2 多路复用
健康检查内置 Health Check
生产就绪

9. 参考资料