GRPC连接机制---长连接分析
gRPC 建立连接后是长连接。 底层基于 HTTP/2,而 HTTP/2 本身就是多路复用的长连接协议。连接一旦建立,默认会一直保持,直到某一方主动关闭或网络中断。
核心机制
1. 连接建立过程
gRPC 客户端启动时,会通过 ClientConn 与目标服务端建立 TCP 连接。如果是 TLS,还要完成 TLS 握手。之后在这个 TCP 连接之上跑 HTTP/2,握手完成后连接就进入就绪状态。
2. 多路复用(关键)
HTTP/2 允许在同一条 TCP 连接上同时跑多个 RPC 调用。每个调用是一个独立的 Stream,有自己的 Stream ID。这意味着:
- 100 个并发 RPC 请求,可能共用 1 条 TCP 连接
- 不需要为每个请求单独建连接、关连接
- 头部压缩(HPACK)让重复的 metadata 传输开销很小
这是 gRPC 和传统“短连接 RPC”最大的区别。传统方式每个请求建一次连接,开销大;gRPC 一次建连,反复复用。
3. 连接保持
gRPC 默认启用了 HTTP/2 Keepalive。客户端会定期发送 PING 帧,确认连接还活着。如果服务端没响应,客户端会认为连接失效并尝试重连。
Go 的 gRPC 里,keepalive 参数长这样:
grpc.WithKeepaliveParams(keepalive.ClientParameters{
Time: 10 * time.Second, // 多久发一次 PING
Timeout: 3 * time.Second, // PING 等多久算超时
PermitWithoutStream: true, // 没有活跃流时也发 PING
})
服务端也有对应的 keepalive 策略,可以设置 MaxConnectionIdle、MaxConnectionAge 等强制回收连接。
什么时候连接会断
虽然是长连接,但以下几种情况会触发断开或重建:
| 场景 | 说明 |
|---|---|
| 空闲超时 | 服务端配置了 MaxConnectionIdle,空闲太久会关 |
| 强制老化 | 服务端配置了 MaxConnectionAge,到时间主动断,用于负载均衡 |
| 网络抖动 | TCP 连接中断,客户端自动重连 |
| 服务端重启 | 连接断开,客户端按 backoff 策略重试 |
| 客户端主动关闭 | 调用 ClientConn.Close() |
一个常见的误解
有人以为“gRPC 是长连接,所以不用管连接管理”。实际上:
连接是长连接,但 RPC 调用不是。 每次 RPC 调用仍然是一个独立的请求-响应周期,有自己的 deadline、metadata、状态码。连接复用只是省掉了 TCP/TLS 握手开销,不代表调用之间共享状态。
负载均衡需要额外配置。 如果服务端是多实例,一条长连接只会打到其中一个实例。要真正做负载均衡,通常需要配合服务发现 + round_robin 等 LB 策略,让客户端维护到多个后端的连接池。
连接数不是越多越好。 有些场景下,成千上万的客户端各自维持一条长连接,服务端 fd 和内存压力会很大。这时候服务端会用 MaxConnectionAge 强制连接定期重建,配合负载均衡把流量打散。
总结
gRPC 连接是长连接 + 多路复用:建连一次,多个 RPC 并发复用同一条 TCP 连接,靠 HTTP/2 的 Stream 机制隔离。连接默认保持,靠 keepalive 探活,靠服务端的 idle/age 策略回收。你不需要为每个请求手动建连关连,但需要理解连接生命周期,才能正确处理重连、负载均衡和资源回收。

浙公网安备 33010602011771号