gRPC 概述:从 RPC 到高性能微服务通信

大家好,我是这次课程的主讲。在正式讲解加密和性能优化之前,我觉得有必要先把这个基础打牢。gRPC 到底是个什么东西?它为什么值得我们去折腾加密和优化?

说白了,gRPC 就是谷歌开源的一个高性能 RPC 框架。RPC 的全称是 Remote Procedure Call,远程过程调用。你想想看,我们的服务往往分布在不同的机器上,甚至不同的机房。如何让一个服务像调用本地函数一样,调用另一个机器上的方法?这就是 RPC 要解决的问题。

我的经验: 10 年前我在做电商后端时,服务间通信全靠 HTTP + JSON。一条订单详情接口,数据组装需要调用 6 个服务,耗时经常超过 1 秒。后来换成 RPC,同样的逻辑只要 200 毫秒。我第一次感受到了 RPC 带来的性能冲击。

RPC 基础:为什么需要 RPC?

没有 RPC 的年代,服务间怎么通信?最常见的就是 HTTP 接口,发个 POST 请求,拿回 JSON。这样做有什么问题?

  • 性能开销大:HTTP 报文头太啰嗦,动不动几百字节。高并发场景下,这个开销很要命。
  • 序列化效率低:JSON 是文本协议,解析慢、体积大。二进制协议明显更快。
  • 没有统一的接口契约:你依赖一个文档,文档和实际实现经常不一致。
  • 缺乏流式支持:想做个大文件传输或实时推送?传统 REST 很难优雅实现。

RPC 就是来解决这些问题的。它让你像调用本地函数一样调用远程方法。一切细节——网络传输、序列化、寻址——被框架封装了。

核心思路: RPC 的核心目标只有一个——让远程调用尽可能快、尽可能透明。

gRPC 架构:一根管道,多种玩法

gRPC 的架构其实不复杂。一个中心化的服务端,多个客户端。客户端调用 Stub(桩代码),Stub 通过网络发给服务端。服务端收到后执行真正的逻辑,返回结果。

我把它画成了一幅图,你看看就明白了。

gRPC 核心架构 客户端应用程序 gRPC Stub HTTP/2 通道 协议缓冲区 (序列化) 一元调用 / 流式 服务端应用程序 gRPC Server HTTP/2 通道 协议缓冲区 (反序列化) 一元调用 / 流式 客户端通过 Stub 和 HTTP/2 通道与服务端通信,数据序列化使用 Protocol Buffers

这套架构有几个关键点:

  • HTTP/2 是传输层基础:支持多路复用、头部压缩、服务端推送。这是 gRPC 性能远好于 HTTP/1.1 的底层原因。
  • Protocol Buffers 是序列化方案:二进制格式,比 JSON 小 3-10 倍,序列化速度也快很多。
  • 支持四种通信模式:一元 RPC(请求-响应)、服务端流式、客户端流式、双向流式。

Protocol Buffers 简介:写个 .proto 文件就完事了

Protocol Buffers(简称 protobuf)是 gRPC 的接口定义语言。你定义好 .proto 文件,然后 protoc 编译器帮你生成代码。就这么简单。

syntax = "proto3";

package myapp.v1;

// 用户服务
service UserService {
  // 一元调用:获取用户信息
  rpc GetUser(GetUserRequest) returns (User);
  
  // 服务端流式:批量获取用户列表流
  rpc ListUsers(ListUsersRequest) returns (stream User);
  
  // 客户端流式:批量创建用户
  rpc CreateUsers(stream CreateUserRequest) returns (CreateUserResponse);
}

// 请求消息
message GetUserRequest {
  int32 user_id = 1;
}

// 用户实体
message User {
  int32 user_id = 1;
  string name = 2;
  string email = 3;
}
避坑指南: 我遇到过有人在 .proto 文件里写了很多复杂的嵌套结构,生成出来的代码文件巨大,编译时间飙升。能扁平化就扁平化。字段编号也尽量从 1 开始连续编号,否则编码体积会变大。

protobuf 为什么快?核心两点:

  1. 二进制编码:没有 JSON 的大括号、引号、冒号。字段通过编号标识,解析时直接按 offset 跳过去。
  2. 编码紧凑:Varint 编码让小整数只占 1 字节。0 和 1 存成 1 字节,而不是 JSON 的 "0"(1 字节字符 + 引号 = 3 字节)。
特性 Protocol Buffers JSON
编码格式 二进制 文本
体积(相同数据) 约 1/3 ~ 1/10 基准
序列化速度 快 10-30 倍 较慢
可读性 不可读 可读
Schema 验证 编译期强校验 运行时检查
向后兼容 支持(字段编号) 需手动处理

gRPC vs REST:不是一个维度的东西

很多人问我:“gRPC 和 REST 哪个好?” 我的回答是:它们服务于不同场景。但如果你要做高并发、低延迟的内部服务通信,gRPC 优势非常明显。

对比维度 gRPC REST (HTTP/JSON)
传输协议 HTTP/2 HTTP/1.1 或 HTTP/2
数据格式 Protocol Buffers JSON / XML
接口定义 .proto 文件(强契约) OpenAPI / Swagger(文档)
流式支持 原生支持(4种模式) SSE、WebSocket(非原生)
浏览器支持 需 gRPC-Web 或 proxy 原生支持
工具生态 不如 REST 丰富 极其丰富
适用场景 微服务内部、高性能后端 外部 API、浏览器客户端
给我的启示: 我们团队曾经尝试用 REST 做实时数据推送,写了一大堆 WebSocket 适配代码,维护成本很高。后来换成 gRPC 双向流,代码量少了 60%。不是 REST 不好,而是用错了场景。

为什么 gRPC 在性能上能甩开 REST 几条街?我给你算笔账:

  • 一个简单的 GetUser 接口,gRPC 的 protobuf 编码后约 30 字节,而 JSON 要 200+ 字节。
  • HTTP/2 多路复用让同一个连接能同时处理上百个请求,不用排队等。
  • 头部压缩让每次请求的额外开销从 800 字节降到几十字节。