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 打开分析

抓包后重点关注以下三个时间戳:

  1. SYN 发出时间 → 判断客户端是否发出了连接请求。
  2. SYN-ACK 到达时间 → 如果未收到,说明中间网络或目标端口不通;如果收到但延迟很大,说明链路拥塞或丢包重传。
  3. 应用层数据首包到达时间 → 如果 TCP 握手完成但应用数据迟迟不到,说明服务端处理缓慢。

原因定位

使用故障树法逐层收敛根因。以下为网络超时类错误的标准故障树:

故障树分析(FTA)—— 网络超时
├─ ① 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 握手完成,但应用数据延迟到达 服务端慢查询 / 连接池满 检查工具服务端日志
网络超时排查流程 现象识别 数据采集(抓包) 故障树排查 TCP / SSL / 数据读取 超时参数排查 connect / read / write 修复动作 重试策略调整 复测 → 预防 提示:抓包后优先确认故障树节点归属,再检查超时参数配置,避免盲目调大超时掩盖根因

修复动作

根据定位结果执行对应修复措施:

  • 防火墙/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()

复测

修复后按以下步骤验证:

  1. 单次复现:使用与故障时相同的参数和负载发起一次调用,确认不再超时。
  2. 压力复测:使用 wrk 或 locust 模拟实际并发场景,观察超时率是否归零。
  3. 日志检查:确认 Agent 日志不再出现 TimeoutError,重试计数器未触发。
  4. 网络抓包验证:再次抓包确认 TCP/SSL 阶段时序改进,传输延迟在预期范围内。

预防

  • 设置链路超时基准线:上线前使用 ping 和 curl -w 测量延迟与最大响应时间的 P99 值,据此制定超时参数。
  • 启用多级超时:不要只依赖单一超时,将连接、读取、写入分开配置,避免一个长请求阻塞整条链路。
  • 监控与告警:Agent 端对超时错误做 metrics 采集(Prometheus 计数),超时率超过 1% 时触发告警。
  • 定期演练:在预发环境中人为注入延迟或丢包,验证重试和断路器是否按预期生效。
  • 更新重试策略:根据线上超时分布动态调整退避参数和重试次数,避免过度重试加重服务端压力。