gRPC 和 REST 有什么区别?微服务间通信该怎么选?
简化版
**REST 和 gRPC 是微服务间通信的两种主流方式,核心区别在「协议、数据格式、性能、契约」:**REST 基于 HTTP/1.1 + JSON(文本、人类可读、通用),gRPC 基于 HTTP/2 + Protobuf(Protocol Buffers,二进制)。gRPC 的优势:① 性能高——Protobuf 是二进制、体积小、序列化快,HTTP/2 支持多路复用(一个连接并发多请求)、头部压缩;② 强契约——用 .proto 文件定义接口和消息结构,编译生成各语言的客户端/服务端代码(强类型、跨语言一致);③ 支持流式——双向流、客户端流、服务端流(REST 传统请求-响应做不到)。REST 的优势:① 通用简单——基于 HTTP + JSON,浏览器/任何 HTTP 客户端都能调,调试方便(curl/Postman);② 生态成熟——工具、文档、缓存、网关全套支持。怎么选:对外开放的 API(给前端/第三方)用 REST(通用、易调试);微服务内部之间的高频调用用 gRPC(性能、强契约、流式);很多公司「外部 REST + 内部 gRPC」混用。
详细版
gRPC vs REST 对比:
| 维度 | REST | gRPC |
|---|---|---|
| 协议 | HTTP/1.1(通常) | HTTP/2 |
| 数据格式 | JSON(文本) | Protobuf(二进制) |
| 性能 | 一般(文本大、解析慢) | 高(二进制小、快) |
| 契约 | 弱(靠文档/OpenAPI) | 强(.proto 生成代码) |
| 流式 | 不支持(请求-响应) | 支持(双向流/客户端流/服务端流) |
| 可读性 | 好(人能读 JSON) | 差(二进制) |
| 浏览器直接调 | 能 | 不能直接(需 grpc-web) |
| 跨语言 | 通用 | 通用(proto 生成各语言代码) |
| 调试 | 方便(curl/Postman) | 需专门工具(grpcurl) |
// gRPC 用 .proto 定义接口和消息(强契约)
syntax = "proto3";
message UserRequest { int64 id = 1; }
message UserResponse { int64 id = 1; string name = 2; int32 age = 3; }
service UserService {
rpc GetUser(UserRequest) returns (UserResponse); // 一元调用
rpc ListUsers(UserRequest) returns (stream UserResponse); // 服务端流
rpc Chat(stream Message) returns (stream Message); // 双向流
}
// → 编译后生成 Java/Go/Python 等的客户端和服务端桩代码
REST:GET /users/123 → { "id": 123, "name": "Tom", "age": 18 }(JSON)
gRPC:userService.getUser(request) → 强类型的 UserResponse 对象(Protobuf 二进制传输)
⚠️ gRPC 和 REST 不是「谁取代谁」,而是「各有适用场景」,很多架构是「对外 REST + 对内 gRPC」混用。对外的 API(给浏览器前端、给第三方开发者)优先 REST——因为它基于通用的 HTTP + JSON,任何客户端都能调、浏览器能直接用、调试方便(Postman/curl)、生态成熟(缓存、网关、文档工具全套),而 gRPC 的二进制、HTTP/2、需要 proto 文件对外部使用者不友好(浏览器还不能直接调 gRPC,要靠 grpc-web 代理)。微服务内部之间的高频调用优先 gRPC——因为内部调用追求性能(Protobuf 二进制小而快、HTTP/2 多路复用)、强类型契约(proto 生成代码,服务间接口一致、编译期检查)、且能用流式(如实时数据推送)。所以答案往往不是二选一,而是「看是对外还是对内」。
完整版教学
一、REST:基于 HTTP + JSON
先理解 REST 的特点:
REST(Representational State Transfer):
基于 HTTP,用 URL 表示资源、HTTP 方法表示操作、JSON 传数据
GET /users/123 查询用户 123
POST /users 创建用户
PUT /users/123 更新
DELETE /users/123 删除
→ 资源导向、HTTP 语义、JSON 数据
特点:
① 通用——基于标准 HTTP,任何 HTTP 客户端都能调
② 人类可读——JSON 是文本,能直接看懂、调试方便
③ 无强契约——接口靠文档约定(或 OpenAPI/Swagger 描述)
没有编译期检查,字段拼错、类型不对运行时才发现
④ 生态成熟——网关、缓存、认证、监控工具全套支持
缺点(相比 gRPC):
① 性能——JSON 文本冗余(字段名重复)、解析慢
② HTTP/1.1——每个请求要占用连接(虽有 keep-alive,但无多路复用)
③ 不支持流式(传统请求-响应模型)
④ 弱契约——接口变更容易出错(客户端不知道服务端改了字段)
REST 基于 HTTP + JSON——URL 表示资源、HTTP 方法表示操作、JSON 传数据(GET /users/123)。特点:通用(任何 HTTP 客户端能调)、人类可读(JSON 文本、调试方便)、无强契约(靠文档/OpenAPI 约定、无编译期检查、字段拼错运行时才发现)、生态成熟。缺点:性能一般(JSON 冗余解析慢)、HTTP/1.1 无多路复用、不支持流式、弱契约。理解「REST 基于 HTTP+JSON(资源导向)、通用+人类可读+生态成熟、但无强契约(靠文档运行时才发现错)+性能一般+不支持流式」,就掌握了 REST 的特点。
二、gRPC:基于 HTTP/2 + Protobuf
再理解 gRPC 的特点:
gRPC(Google Remote Procedure Call):
基于 HTTP/2,用 Protobuf 序列化,用 .proto 定义接口
调用像"调本地方法":userService.getUser(request)
→ RPC 风格(远程过程调用),不是资源导向
三个核心技术:
① HTTP/2:
- 多路复用(一个连接并发多个请求,不用等前一个)
- 头部压缩、二进制帧
- 支持流式(双向流)
② Protobuf(Protocol Buffers):
- 二进制序列化(不是文本 JSON)
- 体积小(不传字段名,用字段编号)、序列化/反序列化快
- 强类型(proto 定义了每个字段的类型)
③ .proto 文件(接口定义 IDL):
- 定义 service(方法)和 message(数据结构)
- 编译生成各语言的客户端/服务端代码(强契约、跨语言一致)
优势:
高性能(二进制 + HTTP/2)、强契约(proto 生成代码)、支持流式
缺点:
二进制不可读、浏览器不能直接调、调试需专门工具、学习成本
gRPC 基于 HTTP/2 + Protobuf——用 .proto 定义接口、调用像调本地方法(RPC 风格)。三个核心技术:① HTTP/2(多路复用一个连接并发多请求、头部压缩、支持流式);② Protobuf(二进制序列化、体积小(不传字段名用编号)、快、强类型);③ .proto 文件(IDL 定义 service 和 message、编译生成各语言代码、强契约跨语言一致)。优势:高性能、强契约、支持流式。缺点:二进制不可读、浏览器不能直接调、调试需专门工具。理解「gRPC 基于 HTTP/2+Protobuf(RPC 风格)、三核心:HTTP/2(多路复用/流式)+Protobuf(二进制小而快强类型)+.proto(生成各语言代码强契约)、优势高性能强契约流式、缺点不可读浏览器不能直接调」,就掌握了 gRPC 的特点。
三、性能差异:为什么 gRPC 更快
深入理解 gRPC 性能更好的原因:
① 数据格式:Protobuf(二进制)vs JSON(文本)
JSON:{"userId": 123, "userName": "Tom"}
→ 字段名"userId""userName"重复传输、文本冗余、要解析字符串
Protobuf:二进制,字段用编号(1, 2)代替字段名、紧凑编码
→ 体积小(可能只有 JSON 的 1/3~1/10)、解析快(直接读二进制)
② 传输协议:HTTP/2 vs HTTP/1.1
HTTP/1.1:一个连接同一时间只能处理一个请求(队头阻塞)
→ 并发要开多个连接
HTTP/2:多路复用——一个连接上并发多个请求(互不阻塞)
→ 连接复用、并发高、头部压缩
③ 综合效果:
Protobuf 小而快 + HTTP/2 多路复用
→ gRPC 的吞吐、延迟通常明显优于 REST(尤其高频、小消息场景)
量化感受(大致):
同样的数据,Protobuf 序列化后可能是 JSON 的 1/3 大小、快几倍
高并发下 HTTP/2 的连接效率也远高于 HTTP/1.1
所以内部微服务高频调用,gRPC 的性能优势很实在
gRPC 更快的原因:① 数据格式 Protobuf(二进制)vs JSON(文本)——JSON 字段名重复、文本冗余、解析慢;Protobuf 二进制、字段用编号、紧凑(可能只有 JSON 的 1/3~1/10)、解析快;② 传输协议 HTTP/2 vs HTTP/1.1——HTTP/1.1 一个连接同时一个请求(队头阻塞),HTTP/2 多路复用(一个连接并发多请求、头部压缩)。综合 Protobuf 小而快 + HTTP/2 多路复用,gRPC 吞吐/延迟明显优于 REST(尤其高频小消息)。理解「gRPC 快因:Protobuf 二进制(小而快,字段用编号)vs JSON 文本冗余、HTTP/2 多路复用(一连接并发多请求)vs HTTP/1.1 队头阻塞、综合吞吐延迟明显优于 REST」,就理解了性能差异的原因。
四、契约与流式
gRPC 的另外两个优势:强契约和流式:
强契约(.proto 生成代码):
.proto 文件定义了接口和消息结构(强类型)
→ 编译生成客户端和服务端的桩代码(各语言一致)
→ 好处:
① 客户端和服务端用同一份契约(proto),接口一致
② 强类型——字段类型编译期检查,不像 JSON 拼错运行时才发现
③ 跨语言——Java 服务端、Go 客户端,用同一份 proto 生成,无缝对接
④ 契约先行——先定义 proto,再各自实现
对比 REST 的弱契约:
REST 接口靠文档(或 OpenAPI)约定,没有强制
服务端改了字段,客户端不知道 → 运行时才出错
流式(HTTP/2 支持):
gRPC 支持四种调用模式:
① 一元(Unary):一次请求一次响应(像普通 RPC)
② 服务端流:一次请求,服务端返回一个流(多个响应)
→ 如实时推送、大结果集分批返回
③ 客户端流:客户端发一个流,服务端一次响应
→ 如上传大文件分块
④ 双向流:客户端和服务端都是流
→ 如实时聊天、双向数据同步
REST 传统请求-响应做不到流式(要靠 WebSocket/SSE 变通)
所以 gRPC 的强契约(proto)和流式是它相比 REST 的独特能力
gRPC 的另外两个优势:① 强契约(.proto 定义接口和消息、编译生成各语言桩代码——客户端服务端用同一份契约、强类型编译期检查、跨语言无缝、契约先行;对比 REST 弱契约靠文档、改字段客户端不知道运行时才出错);② 流式(HTTP/2 支持四种模式:一元、服务端流(实时推送/大结果集分批)、客户端流(上传大文件分块)、双向流(实时聊天);REST 传统请求-响应做不到流式要靠 WebSocket/SSE 变通)。理解「gRPC 强契约(.proto 生成各语言代码、强类型编译期检查、跨语言、契约先行,对比 REST 弱契约靠文档)、流式(四模式:一元/服务端流/客户端流/双向流,REST 做不到要 WebSocket)」,就掌握了 gRPC 的另外两个优势。
五、REST 的优势与适用
REST 也有 gRPC 比不了的优势:
REST 的优势:
① 通用简单——基于标准 HTTP + JSON
任何 HTTP 客户端(浏览器、curl、任何语言的 HTTP 库)都能调
不用生成代码、不用特殊协议
② 人类可读——JSON 文本,调试方便
浏览器直接打开、Postman/curl 一键测、日志能直接看内容
③ 生态成熟——HTTP 生态全套支持
缓存(HTTP 缓存)、网关、负载均衡、认证、监控、API 文档(Swagger)
④ 浏览器友好——浏览器能直接调(gRPC 不能,要 grpc-web 代理)
⑤ 松耦合——客户端和服务端不用共享 proto,独立演进
适用 REST:
- 对外开放的 API(给前端、给第三方开发者)
- 需要浏览器直接调用的
- 需要方便调试、人类可读的
- 简单的、非高频的调用
- 需要利用 HTTP 缓存的
所以 REST 在"通用性、易用性、生态"上强,
对外 API、浏览器交互、调试友好的场景是它的主场
REST 的优势:① 通用简单(标准 HTTP+JSON,任何客户端能调、不用生成代码);② 人类可读(JSON 文本、浏览器/Postman/curl 调试方便);③ 生态成熟(HTTP 缓存、网关、认证、Swagger 文档全套);④ 浏览器友好(gRPC 浏览器不能直接调要 grpc-web);⑤ 松耦合(不用共享 proto、独立演进)。适用:对外开放 API、需浏览器调用、需方便调试、简单非高频调用、需 HTTP 缓存。理解「REST 优势:通用简单(任何客户端能调)、人类可读(调试方便)、生态成熟(缓存/网关/Swagger)、浏览器友好、松耦合;适用对外 API/浏览器交互/调试友好/简单调用」,就掌握了 REST 的优势和适用。
六、怎么选:对外 REST + 对内 gRPC
综合对比,给出选择建议:
选择原则(不是二选一,看场景):
对外的 API(给前端、第三方)→ REST:
- 通用、浏览器能调、调试方便、生态成熟
- 外部使用者不想装 gRPC 工具、不想处理 proto
微服务内部之间的调用 → gRPC(高频/性能敏感时):
- 性能高(Protobuf + HTTP/2)
- 强契约(proto,服务间接口一致、编译期检查)
- 支持流式
- 内部可控(大家都用 gRPC,不用考虑通用性)
典型架构(混用):
浏览器/App ──REST──> API 网关 ──gRPC──> 内部微服务集群
微服务间也用 gRPC
→ 对外 REST(通用友好),对内 gRPC(高性能强契约)
其他考量:
- 团队熟悉度、现有技术栈
- 是否需要流式(要就 gRPC)
- 是否强调调试友好、人类可读(要就 REST)
- 消息大小/调用频率(大量高频小消息 gRPC 优势大)
结论:
没有绝对好坏,对外通用用 REST、对内高性能用 gRPC,混用是常态
选择原则(看场景,不是二选一):对外 API(前端/第三方)用 REST(通用、浏览器能调、调试方便、生态成熟);微服务内部高频/性能敏感调用用 gRPC(性能高、强契约、流式、内部可控)。典型架构混用:浏览器/App ──REST──> API 网关 ──gRPC──> 内部微服务(对外 REST 友好、对内 gRPC 高性能)。其他考量:团队熟悉度、是否需流式(gRPC)、是否需调试友好(REST)、消息大小频率(高频小消息 gRPC 优势大)。理解「选择看场景:对外 API 用 REST(通用友好)、内部高频用 gRPC(高性能强契约流式);典型混用对外 REST 对内 gRPC;考量团队/流式/调试/消息频率」,就掌握了选择建议。
记忆钩子:「REST(HTTP/1.1+JSON)vs gRPC(HTTP/2+Protobuf);gRPC 优势:①性能高(Protobuf 二进制小而快、字段用编号 vs JSON 文本冗余;HTTP/2 多路复用一连接并发多请求 vs HTTP/1.1 队头阻塞)②强契约(.proto 定义接口生成各语言代码、强类型编译期检查、跨语言,vs REST 弱契约靠文档运行时才出错)③支持流式(一元/服务端流/客户端流/双向流,REST 做不到);REST 优势:通用简单(任何客户端能调)、人类可读(调试方便)、生态成熟(缓存/网关/Swagger)、浏览器友好;★选择看场景不是二选一:对外 API(前端/第三方)用 REST、微服务内部高频用 gRPC,典型混用对外 REST 对内 gRPC」。
七、常见误区与追问
- 误区:gRPC 一定比 REST 好、要全用 gRPC。 各有适用场景——gRPC 性能高、强契约、支持流式,适合微服务内部高频调用;REST 通用、浏览器能调、调试方便、生态成熟,适合对外 API;很多架构「对外 REST + 对内 gRPC」混用,不是二选一。
- 误区:gRPC 就是「用 HTTP 传 Protobuf」。 gRPC 是基于 HTTP/2(不是 HTTP/1.1)+ Protobuf + .proto 契约的完整 RPC 框架——HTTP/2 提供多路复用和流式、Protobuf 提供高效二进制序列化、.proto 生成各语言代码提供强契约;三者结合才是 gRPC,不只是数据格式的差异。
- 误区:REST 只能用 JSON。 REST 是一种架构风格(资源导向 + HTTP 语义),数据格式通常是 JSON 但也可以是 XML 等;只是实践中 REST + JSON 是最常见组合;gRPC 则固定用 Protobuf。
- 误区:浏览器可以直接调 gRPC。 浏览器不能直接调原生 gRPC(基于 HTTP/2 的二进制帧、浏览器 API 不支持)——需要 grpc-web(一个代理层,把浏览器的请求转成 gRPC);这也是对外 API 更适合用 REST 的原因之一(浏览器能直接调 REST)。
- 追问:gRPC 为什么比 REST 性能好? 两方面:① 数据格式——Protobuf 是二进制、体积小(字段用编号不传字段名、可能只有 JSON 的 1/3~1/10)、序列化/反序列化快;而 JSON 是文本、字段名重复冗余、解析慢;② 传输协议——gRPC 用 HTTP/2(多路复用,一个连接并发多个请求、不队头阻塞、头部压缩),REST 通常用 HTTP/1.1(一个连接同时一个请求);综合起来 gRPC 吞吐更高、延迟更低。
- 追问:gRPC 的强契约相比 REST 有什么好处? gRPC 用 .proto 文件定义接口和消息结构(强类型),编译生成客户端/服务端各语言的代码——客户端和服务端用同一份契约、接口天然一致、字段类型编译期检查(不像 REST 的 JSON 字段拼错、类型不对要运行时才发现)、跨语言无缝对接(Java 服务端 + Go 客户端用同一 proto);REST 的接口靠文档/OpenAPI 约定,没有强制,服务端改了字段客户端不知道就会出错。
- 追问:什么场景该用 REST,什么场景该用 gRPC? 对外开放的 API(给浏览器前端、第三方开发者)用 REST——通用、浏览器能直接调、调试方便、生态成熟;微服务内部之间的高频/性能敏感调用用 gRPC——性能高、强契约、支持流式、内部可控;需要流式(实时推送、双向通信)用 gRPC;需要人类可读、方便调试、利用 HTTP 缓存用 REST;很多架构对外 REST、对内 gRPC 混用。
八、加强记忆
REST 和 gRPC 是微服务通信的两种主流方式:REST 基于 HTTP/1.1 + JSON(文本),gRPC 基于 HTTP/2 + Protobuf(二进制)+ .proto 契约。gRPC 的优势:① 性能高——Protobuf 二进制、体积小(字段用编号、可能只有 JSON 的 1/3~1/10)、解析快,HTTP/2 多路复用(一个连接并发多请求、不队头阻塞)+ 头部压缩;② 强契约——.proto 定义接口和消息、编译生成各语言代码(客户端服务端契约一致、强类型编译期检查、跨语言无缝,对比 REST 弱契约靠文档、改字段运行时才出错);③ 支持流式——四种模式(一元/服务端流/客户端流/双向流,REST 请求-响应做不到)。REST 的优势:通用简单(任何 HTTP 客户端能调、不用生成代码)、人类可读(JSON 文本、Postman/curl 调试方便)、生态成熟(HTTP 缓存/网关/Swagger)、浏览器友好(gRPC 浏览器不能直接调要 grpc-web)。怎么选(看场景,不是二选一):对外 API(前端/第三方)用 REST(通用友好),微服务内部高频/性能敏感调用用 gRPC(高性能强契约流式),典型架构「对外 REST + 对内 gRPC」混用。一句话「REST(HTTP+JSON,通用/人类可读/生态成熟/浏览器友好)vs gRPC(HTTP/2+Protobuf,性能高/强契约 proto 生成代码/支持流式);gRPC 快因 Protobuf 二进制小+HTTP/2 多路复用;选择看场景:对外 API 用 REST、内部高频用 gRPC,混用是常态」。