Skip to content

RESTful vs RPC vs gRPC 对比

你的团队正在选型微服务通信框架。

后端同事说用 RESTful,简单直观;隔壁组说用 RPC,性能强;架构师推荐 gRPC,说这是未来趋势。

你该听谁的?

今天,我们来彻底搞清楚这三种方案的优缺点,以及如何做出正确的选择。

先理解本质:它们解决的是什么问题?

在说区别之前,我们先搞清楚它们的定位:

┌─────────────────────────────────────────────────────────┐
│              服务通信协议分层                            │
├─────────────────────────────────────────────────────────┤
│                                                         │
│  ┌─────────────────────────────────────────────────┐  │
│  │  应用层:RESTful | RPC | gRPC                   │  │
│  │         (解决:怎么描述接口、传输什么数据)      │  │
│  └─────────────────────────────────────────────────┘  │
│                         ↓                               │
│  ┌─────────────────────────────────────────────────┐  │
│  │  传输层:HTTP/1.1 | HTTP/2 | TCP               │  │
│  │         (解决:数据怎么传输)                   │  │
│  └─────────────────────────────────────────────────┘  │
│                         ↓                               │
│  ┌─────────────────────────────────────────────────┐  │
│  │  编码层:JSON | XML | ProtoBuf | Hessian       │  │
│  │         (解决:数据怎么序列化)                 │  │
│  └─────────────────────────────────────────────────┘  │
│                                                         │
└─────────────────────────────────────────────────────────┘

RESTful、RPC、gRPC 不是同一个维度的东西:

  • RESTful 是一种接口设计风格
  • RPC 是一种调用范式
  • gRPC 是 HTTP/2 + ProtoBuf + RPC 的技术组合

RESTful:资源导向的设计哲学

核心思想

REST(Representational State Transfer)的核心理念是:everything is a resource

操作资源,而不是调用方法:

RESTful 风格:
GET    /users          → 获取用户列表
GET    /users/{id}     → 获取单个用户
POST   /users          → 创建用户
PUT    /users/{id}     → 更新用户
DELETE /users/{id}     → 删除用户

HTTP 方法语义

方法语义幂等安全
GET获取资源
POST创建资源
PUT更新资源(完整)
PATCH部分更新
DELETE删除资源

RESTful 的优势

java
// 1. 简单直观,URL 即资源
// 用户接口
GET    /api/users/123
POST   /api/users

// 订单接口
GET    /api/orders
GET    /api/users/123/orders  // 嵌套资源很自然
java
// 2. 浏览器直接访问
// 调试时可以直接在浏览器输入 URL
https://api.example.com/users/123

// 3. 成熟的工具链
// Swagger/OpenAPI 自动生成文档
// Postman、curl 直接测试

RESTful 的劣势

性能问题:
- JSON 体积大(包含字段名)
- HTTP/1.1 队头阻塞
- 每次请求都要建立连接

功能限制:
- 不原生支持双向通信
- 不原生支持流式响应
- 类型系统弱

RPC:动作导向的调用模式

核心思想

RPC(Remote Procedure Call)的核心理念是:像调用本地方法一样调用远程服务

java
// 本地调用
User user = userService.getUser(123);

// RPC 调用(看起来完全一样)
User user = userService.getUser(123);  // 实际是网络调用

RPC 的分类

类型代表特点
Web RPCgRPCHTTP + 二进制序列化
私有 RPCDubboTCP + 私有协议
SOA RPCThrift多语言支持

RPC 的优势

java
// 1. 性能高
// 二进制序列化,比 JSON 小 5-10 倍
// TCP 长连接,避免重复握手

// 2. 类型安全
// 定义接口文件,所有语言生成类型
interface UserService {
    User getUser(long id);
    List<User> listUsers(string department);
}

RPC 的劣势

调试困难:
- 二进制不可读
- 网络调用不直观

跨语言成本:
- 需要 IDL(接口定义语言)
- 每次改接口都要重新生成代码

前端不友好:
- 浏览器无法直接调用
- 需要网关转换

gRPC:HTTP/2 + ProtoBuf 的强强联合

核心优势

gRPC 解决了 REST 和传统 RPC 的痛点:

┌─────────────────────────────────────────────────────────┐
│                   gRPC 解决了什么?                     │
├─────────────────────────────────────────────────────────┤
│                                                         │
│  RESTful 的问题              gRPC 的解决方案           │
│  ├─ JSON 体积大     →        ProtoBuf 体积小 5-10 倍   │
│  ├─ HTTP/1.1 慢    →        HTTP/2 多路复用            │
│  ├─ 无流式支持     →        原生四种 RPC 模式          │
│  └─ 弱类型         →        强类型 .proto 定义         │
│                                                         │
│  传统 RPC 的问题            gRPC 的解决方案             │
│  ├─ 调试困难       →        grpcurl 工具 + 反射         │
│  ├─ 跨语言麻烦     →        一套 .proto,多语言生成    │
│  └─ 协议私有       →        HTTP/2 标准协议            │
│                                                         │
└─────────────────────────────────────────────────────────┘

ProtoBuf 的类型定义

protobuf
// 定义强类型接口
service UserService {
    rpc GetUser (GetUserRequest) returns (User);
    rpc ListUsers (ListUsersRequest) returns (stream User);
}

message GetUserRequest {
    int64 id = 1;    // 强类型,不能传字符串
}

message User {
    int64 id = 1;
    string name = 2;
    string email = 3;
}

HTTP/2 的多路复用

一次连接,并行请求:

┌─────────────────────────────────────────────────────────┐
│  HTTP/2 连接(多路复用)                                 │
├─────────────────────────────────────────────────────────┤
│                                                         │
│  Stream 1: GET /users/1    ────────────────────→        │
│  Stream 2: POST /users    ───────→ ←──────────         │
│  Stream 3: GET /orders   ──→ ←──                     │
│                                                         │
│  一个连接,并行传输!                                    │
│                                                         │
└─────────────────────────────────────────────────────────┘

选型决策树

┌─────────────────────────────────────────────────────────┐
│                   通信协议选型                           │
├─────────────────────────────────────────────────────────┤
│                                                         │
│  需要浏览器直接访问?                                    │
│     │                                                 │
│     ├─── Yes ──→ RESTful                              │
│     │                                                 │
│     └─── No ───→ 需要高性能微服务通信?                  │
│                    │                                   │
│                    ├─── Yes ──→ gRPC                   │
│                    │                                   │
│                    └─── No ───→ 团队技术栈偏好?        │
│                                   │                     │
│                                   ├─── Java 技术栈 ──→ Dubbo │
│                                   │                     │
│                                   └─── 多语言 ────────→ gRPC │
│                                                         │
└─────────────────────────────────────────────────────────┘

详细选型建议

场景推荐方案原因
前后端分离RESTful浏览器友好,工具链成熟
微服务内部gRPC 或 Dubbo高性能,支持多语言
高并发低延迟gRPCHTTP/2 + ProtoBuf
多语言微服务gRPC一套 IDL,多语言生成
快速迭代内部系统RESTful简单,改动方便
Java 同构系统DubboSpring 生态完善
外部 API 开放平台RESTful通用,生态好
实时流处理gRPC原生支持双向流
移动端调用后端gRPC高性能,省流量

对比总结

┌─────────────────────────────────────────────────────────────┐
│                    三大方案全面对比                          │
├─────────────────────────────────────────────────────────────┤
│                                                             │
│  ┌──────────────┬──────────────┬──────────────┐             │
│  │   RESTful    │     RPC     │    gRPC      │             │
│  ├──────────────┼──────────────┼──────────────┤             │
│  │ HTTP/1.1    │ TCP/HTTP    │ HTTP/2       │             │
│  │ JSON/XML    │ 二进制       │ ProtoBuf     │             │
│  ├──────────────┼──────────────┼──────────────┤             │
│  │    低        │    高        │    最高       │ 性能      │
│  ├──────────────┼──────────────┼──────────────┤             │
│  │    强        │    弱        │    强        │ 类型安全   │
│  ├──────────────┼──────────────┼──────────────┤             │
│  │    好        │    差        │    中        │ 可读性     │
│  ├──────────────┼──────────────┼──────────────┤             │
│  │    原生      │   需要网关   │  需要 gRPC-Web│ 浏览器支持 │
│  ├──────────────┼──────────────┼──────────────┤             │
│  │    无        │    无        │    有        │ 流式支持   │
│  ├──────────────┼──────────────┼──────────────┤             │
│  │    大        │    中        │    大        │ 生态       │
│  ├──────────────┼──────────────┼──────────────┤             │
│  │    快        │    快        │    陡        │ 学习曲线   │
│  └──────────────┴──────────────┴──────────────┘             │
│                                                             │
└─────────────────────────────────────────────────────────────┘

混合使用:现实中的最佳实践

实际项目中,往往会混合使用:

┌─────────────────────────────────────────────────────────────┐
│                    混合架构示例                              │
├─────────────────────────────────────────────────────────────┤
│                                                             │
│                        用户请求                              │
│                            ↓                                │
│                    ┌───────────────┐                        │
│                    │   API Gateway │                        │
│                    │   (RESTful)   │  ← 外部 API           │
│                    └───────┬───────┘                        │
│                            │                                │
│              ┌─────────────┼─────────────┐                 │
│              ↓             ↓             ↓                  │
│        ┌──────────┐ ┌──────────┐ ┌──────────┐              │
│        │  用户    │ │  订单    │ │  商品    │              │
│        │  服务    │ │  服务    │ │  服务    │              │
│        │  gRPC    │ │  gRPC    │ │  gRPC    │              │
│        └──────────┘ └──────────┘ └──────────┘              │
│              │             │             │                  │
│              └─────────────┼─────────────┘                  │
│                            ↓                                │
│                    ┌───────────────┐                        │
│                    │   数据服务    │                        │
│                    │   (内部 RPC)  │                        │
│                    └───────────────┘                        │
│                                                             │
│  架构说明:                                                │
│  - 外部访问:RESTful(通过 API Gateway)                   │
│  - 内部通信:gRPC(高性能)                                │
│  - 协议转换:Gateway 做 REST → gRPC 转换                   │
│                                                             │
└─────────────────────────────────────────────────────────────┘

Spring Cloud Gateway + gRPC

yaml
# Gateway 配置:RESTful → gRPC 转换
spring:
  cloud:
    gateway:
      routes:
        - id: user-service
          uri: grpc://user-service:8080
          predicates:
            - Path=/api/users/**
          filters:
            - StripPrefix=2  # 去掉 /api 前缀

面试追问方向

  • 为什么 gRPC 性能比 REST 高这么多?具体在哪些层面优化了?
  • gRPC 的反射机制是什么?用来做什么?
  • 在微服务架构中,怎么让 gRPC 和现有 REST 服务共存?
  • gRPC 的负载均衡怎么做?客户端负载均衡和代理负载均衡各有什么优缺点?

总结

没有最好的方案,只有最适合的方案:

┌─────────────────────────────────────────────────────────┐
│                   选型决策总结                           │
├─────────────────────────────────────────────────────────┤
│                                                         │
│  RESTful:                                              │
│  ✓ 浏览器友好,工具链成熟                               │
│  ✓ 学习成本低,易于调试                                │
│  ✓ 适合外部 API、CRUD 操作                            │
│                                                         │
│  RPC(Dubbo):                                          │
│  ✓ Java 生态完善                                       │
│  ✓ 与 Spring 深度集成                                  │
│  ✓ 适合 Java 同构系统                                  │
│                                                         │
│  gRPC:                                                  │
│  ✓ 性能最优(HTTP/2 + ProtoBuf)                       │
│  ✓ 多语言支持好                                        │
│  ✓ 原生流式支持                                        │
│  ✓ 适合微服务内部通信、高性能场景                      │
│                                                         │
│  现实建议:                                             │
│  - 外部 API → RESTful                                  │
│  - 内部通信 → gRPC                                     │
│  - Java 同构 → Dubbo                                   │
│  - 都可以 → 协议转换网关统一出口                        │
│                                                         │
└─────────────────────────────────────────────────────────┘

理解每种方案的本质和适用场景,才能做出正确的技术决策。

基于 VitePress 构建