代理变慢时,我不会先换 IP,也不会拿一张宽带测速截图直接给代理定罪。我先回答三个不同的问题:当前设备到测速边缘是否正常?运行任务的机器直连业务目标是否正常?同一台机器通过代理访问同一目标时,又多出了多少连接、等待和传输成本?只有把这三条路径拆开,才有机会定位真正的瓶颈。
这也是我排查“网页能开,但爬虫越来越慢”“换了代理还是慢”“本地测速很快,脚本却超时”时使用的流程。它不依赖一个神奇分数,而是要求相同运行环境、相同目标、相同请求和相近时间窗口下的配对证据。

目录
先说结论:Speedyest 是基础网络基线,不是代理判决书
我会先打开 Speedyest 网络测速,观察 Ping、Download、Upload、Jitter 和 Bufferbloat。当前页面说明测试路径是设备到附近的 Cloudflare 边缘,因此这组结果首先回答的是“这台设备此刻的基础网络状态如何”。
边界必须写在结果旁边:浏览器到底有没有经过我要诊断的代理?如果代理只配置在 curl、Python 容器、Playwright worker 或远程 VPS 里,桌面浏览器的测速不会自动穿过那条代理路径。此时测速正常,只能排除一部分本地接入问题,不能证明代理快;测速异常,也不能自动证明代理慢。
完整测速还可能消耗数百 MB 流量。对移动网络、按量计费 VPS 或拥塞中的生产链路,我不会为了“先看个数字”就反复点击。先确认流量成本和影响范围,再决定是否运行完整测试;很多时候,查看一次基线并做几次小载荷 A/B 请求已经足够决定下一步。
我先冻结比较条件,避免制造伪结论
最常见的错误,是把 Speedyest 的下载 Mbps 与另一个服务器上某个小页面的 curl 速度直接相减。两边的服务器、路径、载荷、连接数和协议都不同,这种数字没有共同分母。我会先建立一张实验卡,至少固定下面这些条件:
- 运行环境:从真正运行爬虫、API 客户端或浏览器自动化的机器测试,不拿个人电脑替代远程 worker。
- 目标与路径:直连和代理都请求同一个已授权 URL,方法、查询参数和响应体保持一致。
- 请求选项:超时、压缩、HTTP 版本、User-Agent、Cookie 和重定向策略相同。
- 时间窗口:直连与代理交替执行,而不是上午测直连、晚上测代理。
- 连接状态:明确本轮测的是新建连接还是复用连接,不把两者混在一个平均值里。
- 业务负载:先用低频、小样本排障;未经授权,不用高并发“压测”第三方目标。
我还会记录 Wi-Fi 或有线连接、是否存在 VPN、后台同步任务、代理地区和会话类型。它们不是装饰信息:只要其中一项在两轮之间变化,差值就可能来自实验本身。
三条路径分别回答什么
| 观测路径 | 它主要回答的问题 | 它不能单独证明什么 |
|---|---|---|
| 设备 → Speedyest 边缘 | 本地接入、当前拥塞、时延/抖动和上下行基线是否明显异常 | 爬虫所在 VPS、代理出口或业务目标是否正常 |
| 任务运行环境 → 业务目标 | 不使用代理时,该运行环境到目标的 DNS、连接、TLS、等待和传输表现 | 代理路径增加了多少成本 |
| 同一运行环境 → 代理 → 同一目标 | 在相同请求条件下,经代理后的阶段耗时和吞吐变化 | 未来所有时段、并发和目标都具有相同表现 |
只有第二、第三条路径适合做成配对 A/B。第一条是环境背景:它帮助我判断是不是连出发点都不稳定,却不能替代真实目标测试。
我用 curl 分段计时,而不是只看 total
curl 的 --write-out 官方说明列出了请求完成后可以输出的计时、响应、字节和速度变量。我会从任务运行节点执行下面的低成本探针。代理 URL 通过受控环境变量提供,命令不会主动打印它;生产环境仍应使用现有密钥注入方式,并避免把进程参数、环境变量或 verbose 日志共享出去。
: "${TARGET_URL:?set an authorized target URL}"
: "${PROXY_URL:?load the proxy URL from a secret source}"
probe() {
mode="$1"
shift
curl "$@" \
--connect-timeout 5 \
--max-time 30 \
--silent --show-error \
--output /dev/null \
--write-out "mode=$mode code=%{http_code} dns=%{time_namelookup} connect=%{time_connect} tls=%{time_appconnect} pre=%{time_pretransfer} ttfb=%{time_starttransfer} total=%{time_total} bytes=%{size_download} speed=%{speed_download}\n" \
"$TARGET_URL"
}
probe direct
probe proxy --proxy "$PROXY_URL"
我不会把其中任何一列简单命名为“代理延迟”。这些字段是一次完整传输中的阶段时间,代理类型和 HTTPS 隧道还会改变阶段含义。我的解释顺序是:
time_namelookup:curl 为这次传输完成名称解析所用的累计时间。使用代理时,它可能首先反映代理主机的解析;目标域名由本地还是代理解析,还取决于代理协议和配置。time_connect:建立底层连接前的累计时间。代理模式下,首先连接的是代理入口,因此这里明显增加时,我优先检查入口距离、拥塞、端口和网络可达性。time_appconnect:TLS 等应用层握手完成前的累计时间。HTTPS 经过代理时,它包含隧道建立后的相关工作,不能把差值全归咎于证书或目标服务器。time_starttransfer:收到第一个响应字节前的累计时间,包含此前网络阶段和目标处理等待。它高,不等于“代理 CPU 慢”。time_total:整个请求耗时,适合观察业务体感,但无法独自说明慢在哪一段。size_download与speed_download:只有确认响应内容和字节规模一致,速度差才有可比性。挑战页、错误页或压缩差异都会让数字失真。
HTTP 200 也不代表两次拿到相同内容。对我控制或明确获准测试的目标,我还会校验内容标记、响应类型和最终字节规模;若代理返回一个更小的拦截页,它可能看起来“更快”,实际上业务已经失败。
我的 A/B 不是先测一批直连,再测一批代理
网络状态会随时间漂移,因此我让直连和代理交替出现。下面五轮只是一组有界 smoke test 起点,不是行业标准,也不等于容量测试。执行前我会确认目标授权和请求成本。
for round in 1 2 3 4 5; do
printf 'round=%s ' "$round"
probe direct
printf 'round=%s ' "$round"
probe proxy --proxy "$PROXY_URL"
sleep 2
done
我会分别计算配对样本的中位数,保留每轮原始值,而不是只存一个平均数。两个内部指标足够帮助排序,但它们不是标准化评分:
- 代理新增总耗时:代理组
total中位数减去直连组total中位数。 - 吞吐保留比例:代理组
speed_download中位数除以直连组中位数,前提是成功响应和下载字节可比。
如果五轮差异很大,我不会急着扩大流量来“求平均”。我先看失败是否集中在某个出口、某个时段或某个阶段,再决定增加样本、换受控测试对象,还是直接隔离代理。
冷连接和热连接必须分开
上面的每次独立 curl 调用主要观察新建连接路径,也就是更接近冷连接。真实爬虫通常有连接池、HTTP/2 多路复用、会话粘性或长连接。若生产问题只发生在首个请求,可能是 DNS、TCP、代理握手、CONNECT 或 TLS 建连成本;若首个请求正常、持续传输逐渐变慢,则应检查代理负载、出口到目标的链路、丢包、限速和队列。
我要测热连接时,会在实际使用的客户端里复用同一个连接池,并记录“首请求”和“后续请求”,而不是把多个独立 curl 进程误标为热连接。轮换代理和粘性代理也要分开:前者每次可能换出口,后者应在指定会话窗口内保持路径;不先确认产品语义,样本就无法解释。
小页面快,不代表大传输也快
一个几 KB 的健康检查更容易暴露连接和首字节等待,却很难说明持续吞吐。较大的受控文件能观察传输阶段,但会增加流量和目标负担。我会把“小响应时延检查”和“大响应吞吐检查”分成两组,绝不把两种载荷混算。
RFC 6349 的 TCP 吞吐测试框架提醒测试者关注 RTT、瓶颈带宽、TCP 窗口、MTU、单连接/多连接和重复条件。它是 Informational 文档,主要面向受控、可重复的网络测试,不是要求所有公网测速工具遵守的强制标准。我借用的是它的纪律:先定义路径和条件,再解释吞吐;我不会声称 Speedyest 实现了该 RFC,也不会用单次公网结果替代业务链路证据。
我如何从差值判断下一步
| 观察组合 | 我优先怀疑什么 | 下一步动作 |
|---|---|---|
| 基础测速异常,直连目标也慢 | 本地接入、Wi-Fi、ISP、VPS 上游或同机后台流量 | 暂停代理结论,换有线/空闲窗口或从任务节点复核 |
| 基础测速正常,直连目标慢 | 运行节点到目标的路由、DNS、目标处理或区域差异 | 检查直连阶段和目标健康,不先更换代理 |
| 直连正常,代理的 connect 明显增加 | 代理入口距离、入口拥塞、连接容量或端口路径 | 对同一入口复测,并按入口/地区分组,而非混池 |
| connect 接近,代理的 TLS/pretransfer 增加 | 隧道建立、TLS 路径、协议协商或中间设备 | 核对代理类型、CONNECT 行为、HTTP 版本和证书错误 |
| 建连接近,代理的 TTFB 增加 | 出口到目标的路由、目标对该出口的处理或代理排队 | 核对响应内容、出口、目标地区和低频重试结果 |
| 小响应接近,大响应代理明显慢 | 持续吞吐、拥塞、丢包、窗口、MTU 或供应侧限速 | 只在受控目标上比较相同文件,并区分单/多连接 |
| 冷连接慢,复用连接正常 | DNS、TCP、代理握手、CONNECT 或 TLS 建连成本 | 检查连接池和复用策略,不靠无限增加超时掩盖 |
| 空闲时正常,负载时 Ping/抖动上升 | 队列、Bufferbloat、共享链路或代理并发容量 | 降低并发并观察队列;在授权环境做阶梯式容量验证 |
“明显增加”没有一个适用于所有任务的固定毫秒线。搜索结果页、视频流、账号登录和 API 调用的预算完全不同。我的阈值来自该任务的延迟预算、失败成本和历史基线,而不是从文章里抄一个万能数字。
我会保存的最小证据
要让下一位排障者复现结论,我会为每组样本保留下列字段:
- 时间、任务节点、网络接口和测试模式(基础、直连或代理);
- 哈希后的代理 ID、代理类型、期望地区和会话类型;
- 目标的受控标识、请求方法、载荷大小和冷/热连接标签;
- curl 退出码、HTTP 状态、内容匹配、各阶段时间、下载字节和速度;
- 出口观察值、轮次、同机负载,以及本轮是否可与配对样本比较;
- 结论的适用范围:哪个目标、哪个并发、哪个时间窗口。
我不会记录明文代理用户名、密码、完整代理 URL、Cookie、账号令牌或未经授权的响应正文。需要分享日志时,只分享脱敏后的指标和哈希 ID。否则一次性能排障很容易变成凭据泄漏。
几个我会主动拒绝的结论
- “Speedyest 很快,所以代理一定快。”除非浏览器代理路由已经被证明,而且测试路径与业务路径一致,否则这只是基础网络信号。
- “Ping 低,所以下载一定快。”时延和持续吞吐相关但不等价,连接数量、窗口、丢包和拥塞都会改变结果。
- “代理 total 多了 500 ms,所以代理服务器处理花了 500 ms。”差值可能分布在入口连接、隧道、出口路由、目标策略和传输阶段。
- “一次代理响应更快,所以代理优化了目标。”先检查它是否返回了相同内容,而不是更小的错误页或挑战页。
- “五轮通过,所以代理长期稳定。”五轮只够做低成本初诊;长期结论还需要符合业务负载、时段和会话模型的持续观测。
结论
我的顺序始终是:先用基础测速确认出发点,再从真实任务节点直连授权目标,最后在完全相同的请求条件下加上代理,并把 DNS、连接、TLS、TTFB、总耗时和吞吐拆开比较。Speedyest 帮我看环境,curl A/B 帮我看代理路径,目标内容校验则保证我比较的是同一件事。
这样排查的好处,不是得到一句“这个代理快”或“那个代理慢”,而是得到一个能采取行动的结论:该修本地网络、目标路径、代理入口、连接复用,还是持续吞吐。代理性能从来不是孤立属性,它属于“运行环境 + 代理 + 目标 + 载荷 + 时间窗口”这整套组合。