保持连接(Keepalive)

如何在 gRPC 中使用基于 HTTP/2 PING 的保持连接。

概述

HTTP/2 基于 PING 的保持连接是一种即使在没有数据传输的情况下也能保持 HTTP/2 连接活跃的方法。通过定期向连接的另一端发送 PING 帧 来实现。HTTP/2 的保持连接可以提高 HTTP/2 连接的性能和可靠性,但配置保持连接的间隔需要小心。

有一个相关但独立的概念叫做 [健康检查]。健康检查允许服务器报告服务是否健康,而保持连接仅仅是关于连接本身。

背景

TCP 保持连接 是维持连接并检测断开的一个常用方法。当启用 TCP 保持连接时,连接的任何一方都可以发送冗余的包。一旦对方确认收到这些包,连接就被认为是正常的。如果在多次尝试后没有收到确认,连接就会被认为是断开的。

与 TCP 保持连接不同,gRPC 使用 HTTP/2,它提供了强制性的 PING 帧,可以用来估计往返时间、带宽延迟产品,或者测试连接。由于 HTTP/2 的传输是可靠的,TCP 保持连接中的间隔和重试不适用于 PING,因此它们在 gRPC 的 PING 保持连接实现中被替换为超时(相当于间隔 * 重试次数)。

服务所有者并不要求必须支持保持连接。客户端开发者必须与服务所有者协调,确认是否接受特定的客户端设置。服务所有者决定他们愿意支持的功能,包括是否愿意接收保持连接的请求(如果服务不支持保持连接,前几个保持连接的 PING 将会被忽略,服务器最终会发送 GOAWAY 消息,并且调试数据会显示为 too_many_pings)。

配置保持连接如何影响调用

对于快速响应的单次 RPC,保持连接不太可能触发。保持连接主要在长时间运行的 RPC 中触发,如果保持连接检查失败且连接被关闭,RPC 调用将失败。

对于流式 RPC,如果连接被关闭,任何正在进行的 RPC 都会失败。如果调用正在发送数据,流也会被关闭,且任何尚未发送的数据将丢失。

为了避免分布式拒绝服务(DDoS)攻击,在设置保持连接配置时需要谨慎。因此,建议避免在没有调用的情况下启用保持连接,并且客户端的保持连接配置最好不要设置得低于一分钟。

保持连接的常见应用场景

gRPC HTTP/2 保持连接可以在多种场景下非常有用,包括但不限于:

  • 在长时间存在的连接上传输数据,这些连接可能会被代理或负载均衡器认为是空闲的。

  • 在网络不太可靠的情况下(例如移动应用)。

  • 在长时间不活动后使用连接。

保持连接配置说明

选项 可用性 描述 客户端默认值 服务器默认值

KEEPALIVE_TIME

客户端和服务器

PING 帧之间的间隔时间(以毫秒为单位)。

INT_MAX(禁用)

7200000(2小时)

KEEPALIVE_TIMEOUT

客户端和服务器

PING 帧的确认超时时间(以毫秒为单位)。如果发送方在此时间内没有收到确认,它将关闭连接。

20000(20秒)

20000(20秒)

KEEPALIVE_WITHOUT_CALLS

客户端

是否允许客户端在没有任何挂起流的情况下发送保持连接的 PING 帧。

0(false)

N/A

PERMIT_KEEPALIVE_WITHOUT_CALLS

服务器

是否允许客户端在没有任何挂起流的情况下发送保持连接的 PING 帧。

N/A

0(false)

PERMIT_KEEPALIVE_TIME

服务器

服务器接收到连续 PING 帧时,最低允许的时间间隔,且不发送任何数据或头帧。

N/A

300000(5分钟)

MAX_CONNECTION_IDLE

服务器

通道在没有挂起 RPC 的情况下最大空闲时间,超过此时间后,服务器将关闭连接。

N/A

INT_MAX(无限)

MAX_CONNECTION_AGE

服务器

通道存在的最大时间。

N/A

INT_MAX(无限)

MAX_CONNECTION_AGE_GRACE

服务器

通道达到最大年龄后的宽限期。

N/A

INT_MAX(无限)

某些语言可能提供额外的选项,请参考语言示例和其他资源以获取更多详细信息。

语言指南和示例

语言 示例 文档

C++

C++ 示例

C++ 文档

Go

Go 示例

Go 文档

Java

Java 示例

Java 文档

Python

Python 示例

Python 文档