2. 网络超时类错误
现象识别
网络超时是 Agent 调用外部工具时最常见的故障类型。当 Agent 在指定时间内未收到远端响应时,会触发超时异常。典型现象包括:
- 日志关键字:
Timeout exceeded、connect timed out、Read timed out、HTTP 504、curl: (28) Connection timed out - Agent 行为:请求卡住、任务挂起、重复重试后仍失败、最终抛出
ToolExecutionTimeoutError - 用户感知:Agent 无响应、回复延迟超过几十秒、API 调用链断裂
超时错误可能发生在 TCP 连接建立阶段、SSL/TLS 握手阶段或数据读取阶段,不同阶段的表现对后续排查方向有直接指引。
数据采集
快速复现问题后,立即启动抓包工具采集网络流,确保不遗漏关键帧。
抓包黄金命令:使用 tcpdump 在 Agent 所在节点捕获目标工具 IP 的全量流量。
tcpdump -i eth0 host <tool_server_ip> -w timeout_case.pcap
# 抓取完成后按 Ctrl+C 停止,再用 Wireshark 打开分析
抓包后重点关注以下三个时间戳:
- SYN 发出时间 → 判断客户端是否发出了连接请求。
- SYN-ACK 到达时间 → 如果未收到,说明中间网络或目标端口不通;如果收到但延迟很大,说明链路拥塞或丢包重传。
- 应用层数据首包到达时间 → 如果 TCP 握手完成但应用数据迟迟不到,说明服务端处理缓慢。
原因定位
使用故障树法逐层收敛根因。以下为网络超时类错误的标准故障树:
故障树分析(FTA)—— 网络超时
├─ ① TCP 握手阶段超时
│ ├─ 防火墙/安全组丢弃 SYN 包
│ ├─ 目标 IP/端口不可达
│ └─ MTU 过大导致分片丢失
├─ ② SSL/TLS 握手阶段超时
│ ├─ 证书验证过长(CRL/OCSP 超时)
│ └─ 密码套件协商慢
└─ ③ 数据读取阶段超时
├─ 服务端业务处理慢(DB 查询、第三方依赖)
├─ 连接池耗尽导致排队等待
└─ 响应体过大传输时间超过 read_timeout
├─ ① TCP 握手阶段超时
│ ├─ 防火墙/安全组丢弃 SYN 包
│ ├─ 目标 IP/端口不可达
│ └─ MTU 过大导致分片丢失
├─ ② SSL/TLS 握手阶段超时
│ ├─ 证书验证过长(CRL/OCSP 超时)
│ └─ 密码套件协商慢
└─ ③ 数据读取阶段超时
├─ 服务端业务处理慢(DB 查询、第三方依赖)
├─ 连接池耗尽导致排队等待
└─ 响应体过大传输时间超过 read_timeout
排查表:根据故障树节点,对比实际包特征快速定位:
| 阶段 | 抓包特征 | 可能根因 | 确认方法 |
|---|---|---|---|
| TCP 握手 | 只有 SYN 发出,无 SYN-ACK | 防火墙/路由阻断 | telnet <host> <port> 测试连通性 |
| TCP 握手 | SYN 多次重传后 RST | 端口未监听 / 服务未启动 | nc -zv 检查端口状态 |
| SSL 握手 | ClientHello 后长时间无 ServerHello | 服务端证书链验证超时 | openssl s_client -connect 测试 |
| 数据读取 | TCP 握手完成,但应用数据延迟到达 | 服务端慢查询 / 连接池满 | 检查工具服务端日志 |
修复动作
根据定位结果执行对应修复措施:
- 防火墙/ACL 阻断:加入白名单或开放端口策略,验证连通性。
- 服务端未启动/端口错误:检查工具 URL 和端口配置,重启服务。
- SSL 握手慢:禁用 OCSP stapling 或缩短证书链,启用会话复用。
- 服务端处理慢:优化工具端查询或缓存,增加服务端并发能力。
- 超时参数不合理:根据抓包计算的 RTT 和最大响应时间合理调整
connect_timeout、read_timeout、write_timeout。典型配置示例:
# Python httpx / aiohttp 示例
tool_client = httpx.Client(
timeout=httpx.Timeout(
connect=10.0, # 连接建立超时
read=30.0, # 读取数据超时
write=15.0, # 发送数据超时
pool_timeout=5.0 # 连接池等待超时
)
)
重试策略
超时错误通常具有临时性,合理运用重试策略可大幅提升系统韧性:
| 策略 | 适用场景 | 建议值 |
|---|---|---|
| 固定间隔重试 | 瞬时网络抖动 | 重试 2~3 次,间隔 1s |
| 指数退避 | 服务端过载或网络拥塞 | base=1s, factor=2, max=30s |
| 抖动退避 | 防止惊群效应 | 退避值 ±30% 随机 |
| 断路器 + 退避 | 连续超时 ≥5 次后熔断 | 熔断窗口 60s |
在 Agent 配置中集成重试回调:
from tenacity import retry, stop_after_attempt, wait_exponential
@retry(stop=stop_after_attempt(3),
wait=wait_exponential(multiplier=1, min=2, max=30))
def call_external_tool(url, payload):
response = http_client.post(url, json=payload, timeout=15.0)
response.raise_for_status()
return response.json()
复测
修复后按以下步骤验证:
- 单次复现:使用与故障时相同的参数和负载发起一次调用,确认不再超时。
- 压力复测:使用
wrk或locust模拟实际并发场景,观察超时率是否归零。 - 日志检查:确认 Agent 日志不再出现
TimeoutError,重试计数器未触发。 - 网络抓包验证:再次抓包确认 TCP/SSL 阶段时序改进,传输延迟在预期范围内。
预防
- 设置链路超时基准线:上线前使用
ping和curl -w测量延迟与最大响应时间的 P99 值,据此制定超时参数。 - 启用多级超时:不要只依赖单一超时,将连接、读取、写入分开配置,避免一个长请求阻塞整条链路。
- 监控与告警:Agent 端对超时错误做 metrics 采集(Prometheus 计数),超时率超过 1% 时触发告警。
- 定期演练:在预发环境中人为注入延迟或丢包,验证重试和断路器是否按预期生效。
- 更新重试策略:根据线上超时分布动态调整退避参数和重试次数,避免过度重试加重服务端压力。