This repository has been archived on 2026-05-24. You can view files and clone it. You cannot open issues or pull requests or push a commit.
Files
all-in-kingsoft/hzh/MS/06-gRPC/01-协议与架构.md
T

162 lines
6.1 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
---
tags: [grpc, http2, protocol-stack, multiplexing]
create time: 2026-05-07 16:00
---
# gRPC 协议与架构
## 概述
本文深入讲解 **gRPC 的内部架构**和 **HTTP/2 协议栈层次**。理解这些底层机制后,才能解释「为什么 gRPC 比 HTTP/1.1 REST 更快」、「连接为什么不会泄漏」——不再停留在"听说性能好"的模糊认知层面。
> [!question] 先想一个问题
>
> 微服务之间每秒可能产生数万到数十万次 RPC 调用。如果每次调用都新开一条 TCP 连接,操作系统会耗尽哪些资源?
TCP 握手需要三次交互、端口有数量上限(单进程约 65535)、内核要为每个 socket 维护内存——当并发连接数达到万级时,CPU 花在建立和拆除连接上的时间甚至会超过处理业务的时间。这就是 gRPC **默认复用连接**的设计动机。
## gRPC 整体架构
```mermaid
graph TB
subgraph Client["客户端应用"]
CApp["业务代码"]
CStub["Generated Stub"]
CChan["gRPC Channel"]
CCall["Client Call"]
CApp --> CStub
CStub --> CChan
CChan --> CCall
end
subgraph Network["网络层"]
H2["HTTP/2 Frame Layer"]
HP["HPACK Header Compression"]
LM["Load Balancing Picker"]
NR["Name Resolver"]
CCall --> LM
LM --> H2
H2 --> HP
end
subgraph Server["服务端应用"]
SChan["Server Listener"]
SH2["HTTP/2 Frame Layer"]
SHP["HPACK Header Compression"]
SH2 --> SHP
Handler["Registered Handler"]
SHandler["业务代码"]
SHP --> Handler
Handler --> SHandler
end
CChan <-->|Binary Frames| SChan
```
### 关键组件说明
| 组件 | 职责 |
|------|------|
| **Generated Stub** | 从 .proto 文件编译生成的桩代码,封装了序列化 / 反序列化和网络通信细节 |
| **gRPC Channel** | 逻辑连接抽象,内部管理真实 TCP 连接的创建、复用和健康检查 |
| **HTTP/2 Frame Layer** | 二进制分帧层,将所有数据拆分为轻量级的 Frame 传输 |
| **HPACK** | 头部压缩算法,避免重复传输相同的 metadata 字段 |
> [!tip] Go 实现细节
>
> Go 中每个 gRPC Channel 底层维护一个 **transport 连接池**,由负载均衡器动态分配 SubConn。你可以显式设置 `WithBlock()` 超时来避免启动时的无限等待:
>
> ```go
> conn, err := grpc.DialContext(ctx, target,
> grpc.WithBlock(),
> grpc.WithTimeout(5*time.Second),
> )
> ```
## HTTP/2 的关键特性
gRPC 不是一种新协议,而是 **Protocol Buffers + HTTP/2 的绑定规范**。HTTP/2 为 gRPC 提供了三个核心能力:
| 特性 | HTTP/1.1 | HTTP/2 | gRPC 收益 |
|------|----------|--------|-----------|
| **多路复用** | 一个连接只能处理一个请求(除非 SPDY) | 一个 TCP 连接上并行的多个 Stream | 无需连接池,连接复用率极高 |
| **头部压缩** | 明文 Head,重复字段多 | HPACK 算法压缩 | 减小传输体积,降低延迟 |
| **二进制分帧** | 文本协议,解析慢 | 二进制 Frame,解析快 | 双方不需要手写解析逻辑 |
### 多路复用演示
```mermaid
sequenceDiagram
participant C as Client
participant H2 as HTTP/2 Connection
participant S as Server
Note over C,S: 一个 TCP 连接,四个并发 Stream
C->>H2: Stream 1: GetOrder(id=1)
S->>H2: Stream 1: Order{...}
C->>H2: Stream 2: GetUser(id=5)
S->>H2: Stream 2: User{...}
C->>H2: Stream 3: CreateItem(...)
S->>H2: Stream 3: Item{id: "new"}
```
> [!keypoint] 关键洞察
>
> HTTP/1.1 开 10 个并行请求需要 10 条 TCP 连接 → 握手开销大、端口耗尽。**一条 HTTP/2 连接就能承载几百个并发 RPC**,这就是 gRPC 在高频内部调用的性能优势来源。
## 协议栈层次
```mermaid
graph LR
App["Application<br/>Business Logic"] --> Stub["Generated Stub"]
Stub --> GRPC["gRPC Framework"]
GRPC --> H2["HTTP/2 Protocol"]
H2 --> TCP["TCP/IP"]
style App fill:#e3f2fd
style Stub fill:#fff3e0
style GRPC fill:#c8e6c9
style H2 fill:#fce4ec
style TCP fill:#f3e5f5
```
每一层解决不同的问题:
| 层级 | 解决的问题 | 类比 |
|------|-----------|------|
| Application | 你写什么业务逻辑 | 写信的内容 |
| Generated Stub | 把业务对象映射为二进制编码 | 翻译官(Proto 定义 = 字典) |
| gRPC Framework | 负责重试、拦截器、流控 | 邮局分拣系统 |
| HTTP/2 | 多路复用 + 头部压缩 + 二进制帧 | 快递包裹的分装规范 |
| TCP/IP | 可靠传输 + 路由寻址 | 公路运输网络 |
## 为什么不只是"更快的 HTTP"
许多开发者误以为 gRPC 的优势只是"用了更快的序列化"。实际上真正的分水岭在于:
> [!summary] gRPC vs HTTP API 的本质差异
>
> | 维度 | HTTP API(REST) | gRPC |
> |------|-----------------|------|
> | **契约先行** | 接口文档滞后于代码 | `.proto` 是单一事实来源 |
> | **类型安全** | JSON 无类型,运行时才暴露 bug | 编译期捕获字段缺失、类型错误 |
> | **代码即 SDK** | 客户端需要手动拼装 HTTP 请求 | 自动生成全语言客户端 Stub |
> | **连接复用** | 需要自行管理连接池 | 框架内置连接复用和负载均衡 |
> | **流式能力** | WebSocket 需额外建通道 | 原生支持双向流,强类型契约 |
> [!question] 带着问题继续读
>
> 既然 gRPC 这么多优势,是不是所有场景都应该用 gRPC?什么情况下 HTTP/JSON 仍然更合适?
答案见 [[02-服务治理/服务间通信]]。对外暴露 API 时,HTTP/JSON 仍然不可替代——因为浏览器的 Native Fetch 无法直接调用 gRPC,第三方接入者也不想安装 Proto 编译器。
## 关联笔记
- [[02-服务治理/服务间通信]] — gRPC 与 REST 的基础对比及选型建议
- [[02-服务治理/容错模式/README]] — 基于此架构的重试、熔断等治理机制
- [[02-Proto设计]] — Proto 文件设计的进阶实践
- [[03-RPC模式]] — 四种 RPC 模式的深度用法
- [[04-拦截器]] — 切面编程和上下文传播