Kubernetes 里用 Envoy 1.29 做前置网关,客户端走 HTTP/2 调流式接口,每 3 到 5 分钟收到一次 RST_STREAM,错误码是 INTERNAL_ERROR,同一条链路改成 HTTP/1.1 后完全正常。

一开始怀疑是「上游连接池复用了一条已被回收的连接」,查了一圈,方向不对。

排查方向其实有限,先把可能性排一排。HTTP/2 的流复用被上游空闲超时打断。还有一种是网关的 max_stream_duration 设得太短。

不容易想到的是,客户端没处理 GOAWAY 直接复用旧连接。

先用 curl 指定 HTTP/2 复现并记录错误码

curl -N --http2 -D h2.txt https://gw.example.com/v1/chat -d @req.json

临时切到 HTTP/1.1 验证链路本身没问题

curl -N --http1.1 -D h1.txt https://gw.example.com/v1/chat -d @req.json

随后把网关的流超时调到大于最长生成时间

grep -n max_stream_duration deploy/envoy.yaml

客户端收到 GOAWAY 后重建连接再重试

go run ./cmd/stream -http1 -retry-on-goaway

这类改动我都写进变更记录,过两周再出问题时能对上号。

恢复的判定其实很直接。连续 30 分钟不再出现 RST_STREAM,流式内容完整,日志里能看到 GOAWAY 后重新建连的记录。

容易忽略的是,降级到 HTTP/1.1 是最快的止血办法,但并发高时连接数会翻倍,长期还是要把流超时和连接池一起调。如果同一现象隔几天又出现,说明根因没找到,别当偶发处理。

作者 9823189