这个现象在 Istio 环境里非常典型,通常不是业务代码的问题,而是连接空闲(idle)后被某一层网络设备回收,而 Envoy 仍然认为连接可用导致的。
你的现象可以总结为:
服务长时间无流量 → 第一次请求失败(Connection Reset / Connection Closed / Upstream Connect Error)→ 重试后恢复正常
这几乎就是「空闲连接失效」的标准特征。
原理分析
在注入 Sidecar 后,请求链路变成:
Client ↓ Envoy Sidecar ↓ Service ↓ Envoy Sidecar ↓ Application实际上业务流量走的是:
App → Envoy → Envoy → App因此会产生大量长连接池(Connection Pool)。
场景1:HTTP 长连接问题
Istio 默认大量使用:
HTTP/2 gRPCHTTP/2 本身是长连接复用。
例如:
Client Envoy ↓ Server Envoy保持一个连接:
2小时期间没流量。
某层LB:
idle timeout=350s连接被干掉。
Envoy没察觉。
下一次请求:
stream creation直接:
RST_STREAM GOAWAY Connection reset然后自动重建。
场景2:DestinationRule 的连接池配置不合理
很多项目会配置:
trafficPolicy:connectionPool:tcp:maxConnections:100但没有配置:
idleTimeout导致:
连接无限长期保留数小时不释放。
最后:
被中间设备干掉Envoy却继续使用。
推荐解决方案
方案1:配置 TCP KeepAlive(最推荐)
在 DestinationRule 中:
apiVersion:networking.istio.io/v1beta1kind:DestinationRulemetadata:name:xxxspec:host:xxxtrafficPolicy:connectionPool:tcp:tcpKeepalive:time:300sinterval:30s效果:
每5分钟发送KeepAlive这是生产环境最常见的解决方案。
方案2:设置 idleTimeout
trafficPolicy:connectionPool:tcp:idleTimeout:300s意思:
5分钟不用 直接关闭连接下一次请求重新建连。
避免使用失效连接。
例如:
trafficPolicy:connectionPool:tcp:idleTimeout:5m方案3:开启重试(推荐同时配置)
apiVersion:networking.istio.io/v1beta1kind:VirtualServicespec:http:-retries:attempts:3perTryTimeout:2sretryOn:connect-failure,reset,gateway-error当出现:
Connection ResetEnvoy自动重试。
用户无感知。
很多生产环境都会开启。
方案4:缩短连接生命周期
trafficPolicy:connectionPool:tcp:maxConnectionDuration:30m定期重建连接。
避免:
连接活几个小时当然也可以组合配置
例如先配置连接池:
trafficPolicy:connectionPool:tcp:idleTimeout:5mtcpKeepalive:time:300sinterval:30s再配合重试:
retries:attempts:3retryOn:connect-failure,reset这样基本可以彻底解决「长时间无访问,首次请求失败,第二次恢复」的问题。