bigywater.tech
gRPC · 40

服务端 max_connection_age:主动断开长连接的好处

让服务端定期结束长连接有什么好处?到期时线上发生什么?在途的长流会怎样?会不会引起失败或延迟抖动?这篇用抓包代理和持续负载把它们都看一遍。

1.87 ~ 2.21 秒
MaxConnectionAge = 2 秒时,30 条连接第一个 GOAWAY 到达的时刻范围
失败 0 / 8 条连接
年龄 500 ms 的持续负载 4 秒里,失败调用数与建立的连接数
4.02 秒 vs 2.50 秒
宽限默认(无限)时长流跑完;宽限 1 秒时服务端第一次发送失败的时刻

机制

实测 · 本机执行输出
  1.053 秒:S→C GOAWAY 最后流 2147483647,错误码 NO_ERROR,附加数据 "max_age"
  TCP 连接数 1;客户端状态 IDLE

年龄到期时服务端发 GOAWAY(附加数据 max_age),不再接受新流;客户端之后遇到调用会重新建连,而不是继续用这条连接。

抖动

实测 · 本机执行输出
  观察到 30 个连接的第一个 GOAWAY:最早 1.87 秒、最晚 2.21 秒、平均 2.05 秒(MaxConnectionAge = 2 秒)

服务端给年龄加 ±10% 的随机抖动,避免所有连接同时重建。

在途的流

实测 · 本机执行输出
  宽限默认(无限)       客户端 4.02 秒时结束、收到 8 条消息(服务端共发 8 条),结束时:io.EOF(流正常结束,状态为 OK);服务端发送一直成功
  宽限 1 秒         客户端 3.07 秒时结束、收到 5 条消息(服务端共发 8 条),结束时:code=Unavailable message="closing transport due to: connection error: desc = \"error reading from server: E…";服务端第一次发送失败在 2.50 秒

宽限(MaxConnectionAgeGrace)默认是无限,在途的流不受影响;设了宽限,到期加宽限之后连接被强制关闭,长流会被打断。

代价

实测 · 本机执行输出
  没有设置                     总调用 142588;失败 0;TCP 连接共 1 条;p50 210 µs、p99 418 µs、最慢 34211 µs
  MaxConnectionAge 500 ms  总调用 144272;失败 0;TCP 连接共 8 条;p50 209 µs、p99 395 µs、最慢 29301 µs

本机回环上频繁更换连接没有造成失败或可见的延迟变差;真实网络里要加上重建连接的握手成本。

Idle 与 Age

实测 · 本机执行输出
  MaxConnectionIdle = 300 ms 4 次调用(间隔 1 秒):失败 0;TCP 连接共 4 条;最后的客户端状态 IDLE
  MaxConnectionAge = 1.5 秒   4 次调用(间隔 1 秒):失败 0;TCP 连接共 2 条;最后的客户端状态 IDLE

MaxConnectionIdle 只回收空闲连接,MaxConnectionAge 不管忙闲都定期更换,常用来重新做负载均衡、让新证书或新后端生效。

分步演示

主动断开长连接
本步的对象

    本文用到的工具与边界

    • 本机 macOS 27 arm64 / Go 1.27.1 / grpc-go v1.84.0 / protobuf-go v1.36.12 / golang.org/x/net v0.57.0 / protoc 36.2(Homebrew);服务端和客户端都是本机起的 Go 进程(127.0.0.1,端口 9800 以上,不访问任何外部服务);需要看线上字节时用我自己写的 TCP 抓包代理加 golang.org/x/net/http2 的 Framer 解析 HTTP/2 帧;计时用 time.Now 或 perf_counter,数字每次运行会有小幅抖动。GOAWAY 的时刻和内容来自抓包代理;连接数是代理接受的 TCP 连接数;抖动范围、max_age/max_idle 附加数据读自 internal/transport/http2_server.go;长流那一节只跑了一次,时刻有数十毫秒的误差
    • 没有验证:真实负载均衡器(如 Kubernetes Service、Envoy)在连接更替时的行为;TLS 下重建连接的成本;客户端使用 pick_first 与 round_robin 时更替后的后端分布(第 16 篇有一部分);为什么长流的客户端比服务端的发送失败晚约 0.6 秒才报错(没有查);MaxConnectionAge 与 keepalive 的相互作用
    京ICP备2026067502号-1京公网安备11010502063487号