简介:gRPC 与 RESTful API 的取舍是微服务架构中的高频决策。本文从序列化开销、传输协议、接口契约与开发体验四个维度系统对比两者,澄清“性能固定提升数十倍”“多路复用为 gRPC 独有”等常见误区,并给出按场景判断的选型清单,帮你用数据而非传说做出更稳妥的技术决策。
一个直观的类比:RESTful API(典型形态是 JSON over HTTP)像发快递——URL 是收件地址,报文是包裹,拆开就能看懂,任何收件人都知道怎么处理;gRPC 更像企业内部专线——收发双方事先签好一份”运输协议”(接口契约),货物统一装进标准化集装箱(二进制编码)运输,不需要照顾”人眼是否看得懂”,只照顾”机器处理得快不快”。
因此两者的差异不是”谁更先进”,而是优先级不同:
如果你的系统每天都在内网微服务之间跑成千上万次调用,JSON 的解析与传输开销确实值得认真审视——但它到底占多少 CPU、耗多少带宽,要靠测量说话,不能一上来就拍脑袋下结论。下面逐层拆开来看。
JSON 的好处是实打实的:人能直接读懂,打开浏览器控制台,请求与返回的字段名、字段值一目了然,前后端联调和问题排查都省事。这是它在开放接口领域长期占据主流的根本原因。
但计算机处理这些文本是有成本的,主要集中在两处:
序列化/反序列化的 CPU 开销。发送端要把对象转成带引号、冒号、大括号和转义字符的文本;接收端要做字符串匹配定位字段,再把文本数值还原成数值类型。单次调用微不足道,但当调用频率和消息规模上去之后,这部分工作就不能忽略了。具体占比多少,取决于消息结构、字段数量、数值密度和所用的解析库,不能武断地说”至少占一半 CPU”。
带宽开销。JSON 每条消息都要把完整字段名原样传一遍。例如下面这条消息:
{"order_id": 10086,"status": "PAID","total_price_cents": 259800,"created_at": 1735660800000}
order_id、total_price_cents 这些 key 会随着每一条消息反复传输。单条看毫不起眼,内网来回跑上几亿次,累积的流量是实打实的。当然,调用量不大的时候,这些开销未必值得计入成本。
gRPC 默认搭配 Protocol Buffers。它的思路是:先用一份接口定义文件(IDL)把消息结构固定下来,编译时生成强类型代码;线上传输时不再携带字段名,而是用字段编号标识字段,值以紧凑的二进制形式编码。对应上面那条订单消息,契约大致长这样:
syntax = "proto3";message Order {int64 order_id = 1;string status = 2;int64 total_price_cents = 3;int64 created_at = 4;}
传输内容里,order_id 这个名字不存在了,只有”字段 1 是一个整数”和它的值;小数值用变长整数编码,往往一两个字节就装得下。字段名只活在契约文件和生成的代码里,不占带宽。
“体积缩到 JSON 的三分之一、解析快几倍到几十倍”——不能一概而论。 数值、枚举密集的消息收益明显;但如果消息主体是大段文本(长评论、富文本、base64 编码的图片),字符串该怎么传还是怎么传,体积差距会明显收窄;若链路上已有压缩,差距还会进一步被抹平。倍数是测出来的,不是背出来的。
“二进制反序列化等于直接映射到内存”——不成立。 解码器仍要逐字段读取、分配对象、做边界检查和兼容性处理,流程一个都不少。它省掉的是”字符串键匹配、文本转数值”这类高成本低价值的环节,而不是省掉整个解析过程。
“换上 gRPC 吞吐就能翻倍”——取决于瓶颈在哪。 序列化只是链路上的一环。如果压测显示瓶颈在数据库、下游依赖或锁竞争上,换编码方式收益寥寥。正确姿势是先量化:序列化 CPU 占比多少、带宽里字段名占多少,这些开销如果正好卡住了吞吐量,换一种更合适的编码,收益才会明显。
RESTful 接口若部署在 HTTP/1.1 上,同一个连接里的响应必须按请求顺序返回,前面一个请求慢了,后面的响应就得跟着等,这是很多”偶发超时”的根源之一。
常见解法是连接池:把并发请求分散到多条连接上,各自排队。它确实有效,但连接不是越多越好:
HTTP/2 把报文切成二进制帧,多个请求的帧可以在同一条 TCP 连接上交错传输,这就是多路复用;再配合头部压缩,重复元数据也不再逐条全量传输。
对 gRPC 而言,这意味着你和目标服务之间维持少量长连接就能承载大量并发调用,省掉了反复建连握手的开销,也减轻了连接池的调参负担。
多路复用是 HTTP/2 的能力,不是 gRPC 的专利。 RESTful 接口跑在 HTTP/2 上同样能享受多路复用。区别在于:gRPC 天生构建在 HTTP/2 之上,开箱即用;而现实中大量 REST 服务仍部署在 HTTP/1.1 上——既有历史包袱,也有客户端、网关、中间件兼容性的现实约束。比较”RESTful 与 gRPC”时,经常实际是在比较”HTTP/1.1 与 HTTP/2 的典型部署形态”,这笔账要诚实分开算。
同一条连接上的请求,并非”完全互不影响”。 TCP 保证字节流按序交付,一旦丢包,这条连接上所有流都要等重传补齐——这就是 TCP 层的队头阻塞,多路复用解决不了它。此外,连接级流量控制窗口与带宽是所有流共享的资源,单个慢流也可能挤占别人。所以”一条连接包打天下”同样是过度承诺,高并发下 gRPC 也需要连接与并发参数的调优。
这一层在选型时容易被低估,但长期影响最大。
RESTful 的协作方式是”资源 + 文档”。 用 HTTP 方法表达操作意图,用 URL 表达资源,靠接口文档(或通用的接口描述规范)在团队间传递契约。优点是上手快、调试方便、HTTP 缓存体系可直接复用、浏览器原生可调;缺点是契约约束相对松散——字段拼错、类型传错,往往要到运行时才暴露。
gRPC 的协作方式是”契约先行 + 代码生成”。 .proto 文件就是唯一事实源,编译期生成各语言的客户端/服务端桩代码,类型错误在编译阶段就被拦下。它还内置了几项服务间通信的高频刚需:
代价同样明确:报文是二进制帧,抓包不能直接肉眼阅读,排障高度依赖结构化日志、链路追踪和专用工具;浏览器无法直接调用原生 gRPC,通常需在边缘做协议转换或使用专门适配方案。这些开发体验上的”摩擦”,选型时要一并计入成本。
把上述分析收敛成几个可以直接回答的问题:
| 判断维度 | 倾向 RESTful | 倾向 gRPC |
|---|---|---|
| 主要调用方 | 浏览器、移动端、第三方 | 内部服务、机器对机器 |
| 通信形态 | 资源型 CRUD、可缓存读 | 高频调用、流式推送、双向交互 |
| 流量规模 | 中低频 | 内网每日千万级以上 |
| 契约需求 | 开放、宽松演进 | 强类型、多语言代码生成 |
| 排障方式 | 要求肉眼可读 | 可接受工具化排障 |
三点补充判断:
回到最初的问题,两者的区别可以收敛为四组关键词:
它们的”优点”都不是无条件的:gRPC 的效率优势要在高频、内部、机器对机器的调用里才显著,REST 的通用性优势要在开放、人机协作、生态成熟的场景里才突出。最可靠的做法永远是:先用压测和监控搞清楚瓶颈到底在哪一环,再决定要不要为它换一种更合适的编码与传输方式。技术选型不认传说,只认测量。