1. gRPC 概述:从一次"翻车"说起

先聊点实在的。gRPC 是什么?简单说,是 Google 开源的一个高性能远程过程调用框架。但我更喜欢这么理解:它让你写代码时感觉像在调本地函数,实际却跨了网络。

我第一次接触 gRPC 是在做一个微服务改造项目。当时团队用 REST 接口,每个服务间通信都自己拼 JSON、解析 JSON,出个字段变更就得改三四个地方。后来有个同事说:「试试 gRPC 吧」。说实话,我一开始是抗拒的——又要学新工具。但用下来,嗯,真香。

传统 RPC 和 REST,有什么问题?

先看传统 RPC。很多自研 RPC 框架走二进制协议,快是快,但耦合紧。服务端和客户端得用同一个语言、同一套序列化库,换语言就得重写。我参与过一个老项目,服务用 Java,客户端用 C++,两边对数据结构的定义不同,线上出了好几次诡异 bug。

再看 REST。REST 的好处是通用、简单,谁都能看懂 HTTP 请求。但代价也很明显:

  • 序列化开销大:JSON 文本格式,解析慢,体积大。我记得压测时,纯 JSON 序列化能吃掉 30% 的 CPU。
  • 没有强类型约束:接口文档写的是字符串,实际传过来的是个数字,运行时才报错。我在生产上踩过这个坑——前端传了个字段类型不对,后端解析炸了,排查花了两小时。
  • 只支持请求-响应模式:想做个服务端推送?得靠 WebSocket 或轮询,折腾。
我的建议:如果你的服务间调用频繁、数据量大、需要强契约,gRPC 大概率比 REST 合适。但如果是对外暴露给不同语言的客户端,REST 还是更通用。

gRPC 的三板斧

gRPC 之所以能解决上述痛点,靠的是三个核心武器:HTTP/2、Protocol Buffers、双向流。下面逐个说。

1. HTTP/2:多路复用与头部压缩

传统 HTTP/1.1 有个问题:同一个连接上,请求必须排队。一个请求没响应完,后面的得等着。这就是队头阻塞。HTTP/2 引入了多路复用——多个请求共用一条 TCP 连接,互不干扰。

gRPC 底层强制使用 HTTP/2。这意味着你的客户端和服务端之间可以同时发送多个 RPC 调用,而不用建多个连接。另外,HTTP/2 还做了头部压缩(HPACK),省带宽。我在项目里实测过,同样一组接口,从 REST/HTTP/1.1 改成 gRPC,传输数据量减少了 50% 以上,尤其是头部反复传递的场景——比如认证 。

2. Protocol Buffers:紧凑、强类型的契约

Protocol Buffers(简称 protobuf)是 Google 的序列化框架,也是 gRPC 的默认序列化方式。它不是 JSON 那样靠 key-value 文本标记,而是用二进制编码,紧凑到极致。

举个例子——定义一个用户信息结构:

syntax = "proto3";

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

编译生成对应的客户端和服务端代码。关键好处:

  • 字段有编号,传输时只传编号和值,不传字段名。而 JSON 每次都把 "name" 这个字符串传一遍。
  • 类型在编译时就固定了。如果你传了个字符串给 int32 字段,编译直接报错,不会等到运行时崩。
  • 版本兼容容易:新增字段不用改老代码,老客户端看到未知字段就跳过。
我曾经的教训:protobuf 的字段编号一旦用了就别删。删掉后老客户端可能把新字段解析成旧字段,数据全乱。必须用 reserved 关键字标记废弃编号。

3. 双向流:不止是请求-响应

REST 的模型是客户端发请求,服务端回响应,一个来回就结束。gRPC 支持四种调用模式:

模式 描述 适用场景
一元 RPC 客户端发一个请求,服务端回一个响应 普通查询、写入
服务端流式 RPC 客户端发一个请求,服务端回多个响应(流) 批量查询、日志推送
客户端流式 RPC 客户端发多个请求(流),服务端回一个响应 文件上传、批量提交
双向流式 RPC 客户端和服务端各自独立发送流,全双工 聊天、实时协同、视频信令

双向流是我个人最喜欢的功能。比如一个实时监控面板:服务端持续推送 CPU 指标,客户端同时可以发送配置变更命令,双方互不等待。这在 REST 体系里很麻烦,要么轮询,要么 WebSocket + 额外协议。

gRPC 与传统 RPC/REST 对比总结

维度 传统 RPC REST gRPC
传输协议 自定义 TCP/UDP HTTP/1.1 HTTP/2
序列化格式 二进制(私有) JSON/XML Protocol Buffers
接口契约 无或文档 Swagger 等 .proto 文件(强类型)
流式支持 通常不支持 需额外方案 原生支持四种模式
性能(参考) 高 中等 高
跨语言能力 弱 强 强(protoc 生成多语言)

看到表格,你可能想问:gRPC 比 REST 快在哪?我做过一个压测,同样的业务逻辑,gRPC 的 QPS 比 REST(HTTP/1.1 + JSON)高了 3-5 倍,延迟也少 40% 以上。但注意,这主要是指内部服务间调用。如果面向浏览器客户端,REST 依然是主流,因为浏览器 HTTP/2 对 gRPC 的支持还不完整。

一句话总结:gRPC = HTTP/2 长连接 + Protocol Buffers 二进制契约 + 四种流式模式。它让微服务之间的通信更高效、更规范。

gRPC 知识体系一览

下面这张图概括了本章的核心逻辑:gRPC 如何把「定义契约」「生成本地代码」「网络传输」串联起来。你看一遍应该就能理解全貌。

gRPC 核心知识体系 .proto 接口契约 protoc 代码生成 服务端存根 (Server Stub) 客户端存根 (Client Stub) 服务业务逻辑 客户端业务调用 HTTP/2 传输(Protobuf 编码) 开发者只需写 .proto 和服务业务逻辑,其余由 protoc 和 gRPC 框架自动处理。

你看,整个流程非常干净:定义一份 .proto 文件,然后 protoc 自动生成服务端和客户端的存根代码,两边各自实现或调用。底层传输由 gRPC 框架搞定,开发者几乎不用手动拼字节流。

好了,关于 gRPC 是什么、它和传统方案有什么不一样,以及它的三大核心特性,就讲到这里。我个人觉得,gRPC 最大的价值不是速度快,而是让微服务之间的「契约」变得显性、可编译、可验证。这在多人协作的大项目里,能省掉大量沟通和排错成本。希望你对它有个整体的感觉,后面章节我们会一步步搭环境、写第一个 .proto、跑通一个完整的 RPC 调用。