主流 RPC 框架 gRPC、Dubbo、Thrift 该怎么选?
核心结论
选 RPC 框架先定语言生态,再看服务治理需求,最后看性能瓶颈:Java 项目优先 Dubbo,跨语言项目优先 gRPC,遗留系统多协议兼容考虑 Thrift。
三个框架的本质区别
选型之前,先搞清楚它们在通信模型和序列化机制上的根本差异,这决定了它们的性能天花板和适用边界。
通信协议不同:
- gRPC 基于 HTTP/2,天然支持多路复用、流式通信、头部压缩
- Dubbo 默认走 TCP 长连接 + 自定义协议,单连接上传输更紧凑
- Thrift 支持多种传输方式(TSocket、THttp、TFramed),灵活但需要自己选
序列化机制不同:
- gRPC 用 Protobuf,强类型 + 二进制,序列化体积最小,但需要 .proto 文件编译生成代码
- Dubbo 默认 Hessian2,支持多序列化切换(Kryo、Protobuf 等),Java 原生兼容好
- Thrift 用自己的 IDL 生成代码,支持 Binary/Compact/JSON 多种格式
按场景选型
Java 单栈微服务 → Dubbo
Dubbo 的核心优势不在性能,而在服务治理体系的完整度:内置注册中心(ZooKeeper/Nacos)、负载均衡策略(随机/轮询/一致性哈希)、熔断降级、服务分组和版本控制。Spring Cloud Alibaba 生态下,Dubbo 与 Nacos、Sentinel 的整合几乎是零成本。如果团队全是 Java 栈,选 Dubbo 省的是运维和治理的成本。
注意:Dubbo 3.x 已经支持 Triple 协议(基于 HTTP/2),可以和 gRPC 互通,跨语言能力在补齐。
跨语言微服务 → gRPC
gRPC 的跨语言是第一等公民:一个 .proto 文件生成 Go、Java、Python、C++ 等十几种语言的客户端和服务端代码,接口定义即契约。HTTP/2 带来的流式通信(客户端流、服务端流、双向流)是 Dubbo 和 Thrift 不原生支持的特性,适合实时数据推送、大文件分片传输等场景。
代价是调试不方便——二进制协议无法直接用 curl 打,需要 grpcurl 或 grpc-web 做代理;服务治理需要自己搭(配合 Consul/etcd 做服务发现,配合 Jaeger 做链路追踪)。
多协议兼容 / 遗留系统 → Thrift
Thrift 最大的价值是灵活性:传输层可选 TSocket/THttp/TFramed,协议层可选 TBinary/TCompact/TJSON,序列化格式可以混搭。对于既有 C++ 老系统又要对接 Java 新服务的场景,Thrift 的多协议支持比 gRPC 的单一 Protobuf 更容易兼容。但社区活跃度不如 gRPC 和 Dubbo,遇到问题排查成本高。
性能数据参考
同一环境下的 QPS 对比(小型请求体,单连接):
- gRPC (Protobuf):约 35k QPS
- Dubbo (Hessian2):约 28k QPS
- Thrift (TBinary):约 30k QPS
- Feign (JSON/HTTP1.1):约 12k QPS
差距在日常业务中感知不大,瓶颈通常在数据库和 IO 而非框架本身。不要为了 20% 的框架性能差异牺牲 50% 的开发效率。
面试追问方向
- Dubbo 的服务降级和熔断怎么实现?(Sentinel 集成 + mock 机制)
- gRPC 的流式通信在什么业务场景下不可替代?
- Protobuf 和 JSON 序列化的性能差距在什么量级?什么场景下 JSON 更合适?
- Dubbo 3.x 的 Triple 协议解决了什么问题?