“我的请求在超时”,是我们收到的最常见的支持消息之一,也是最不具体的之一。超时是一个症状,不是一个原因。无论是 gateway 没能给你找到一个匹配的出口 IP、你的客户端在一条本需要 8 秒的连接上 5 秒就放弃了、目标站点很慢,还是你自己的容器配错了、根本没触达代理,冒出来的都是同一个错误。
这是一份诊断指南:如何辨认出真正在发生的是其中哪一种,并且按最快找到它的顺序来。它是降低延迟的姊妹篇,那篇讲的是把一套能用的配置变得更快;这一篇讲的是一套正在卡住或失败的配置,以及为什么。
第 0 步:这真的是超时吗?
在诊断之前,先精确分类,因为有三种不同的失败都会被报成”超时”,而它们的修法各不相同:
- 连接超时(connect) —— 你的客户端根本没能与 gateway 建立连接。这指向你这一侧:网络出站、防火墙、主机/端口写错,或容器配置。
- 读取/响应超时(read) —— 你连上了,请求发出去了,但没有响应及时回来。这指向出口或目标:没有匹配的 IP、一台慢的出口设备,或一个慢的目标站点。
- 根本不是超时 —— 一个
407(认证)、一个502(没有 IP 匹配你的过滤条件),或一个卡住的 CAPTCHA 页面。这些常常被那种把一切都捕获成同一个异常的包装代码报成超时。
大多数客户端允许你把连接超时和读取超时明确分开。这么做是价值最高的一步诊断,而且通常只是改一行:
import requests
# (connect_timeout, read_timeout) —— 把它们分开,别只传一个数字r = requests.get(url, proxies=proxies, timeout=(10, 30))如果它在头 10 秒内失败,那是连接问题。如果它挺过了连接、在 30 秒时死掉,那是读取问题。往下读对应的那一节。
原因 1:你的地理过滤太紧了
这是最常见的真实原因,也是最容易修的。
每一个定位标志都会收窄合格出口 IP 的池子。country-us 是从一个巨大的集合里挑。country-us-city-scranton-asn-12345 可能是从几乎没有里挑。当匹配的出口很少或没有时,请求会等待、然后失败,而根据你的客户端不同,这会表现为超时或一个 502。
诊断它的办法是一次放宽一个标志:
# 只用 country 能行吗?curl -x customer-USER-country-us:PASS@p.shifter.io:443 https://api.ipify.org --max-time 30
# 然后把城市加回去做对比curl -x customer-USER-country-us-city-chicago:PASS@p.shifter.io:443 https://api.ipify.org --max-time 30如果只用 country 成功、而更窄的过滤条件超时,你就找到它了。修法: 只保留你的数据确实需要的那点精度。如果你的用例真的需要那座城市,那就预期一个更小的池子和更低的吞吐,并为此做好预算(何时城市级定位很重要讲了什么时候它值这个代价)。
原因 2:你的超时值是按数据中心调的,不是按住宅
紧随其后的第二名,而且它会在那些本来就没坏的请求上制造出”超时”。
住宅流量要经由家庭网络上一台真实的消费者设备路由,所以它有一个数据中心代理没有的延迟下限(住宅 vs 数据中心)。一个 5 秒的总超时,对数据中心完全合理,却会把一个健康的住宅请求拦腰砍断,并把它报成一次失败。
诊断它的办法是先测量再调参:经由代理,为你真实的目标采集 p50 和 p95 延迟(如何测试代理的速度、成功率与位置准确度里有方法)。如果你的超时值低于你的 p95,那就是你自己在制造失败。
修法: 把超时值设在你实测 p95 之上并留出余量,而不是靠猜。作为起点,对住宅来说,连接超时大约 10 秒、读取超时 30 秒或更多是合理的;之后再按你自己的数字收紧。
原因 3:慢的是目标,不是代理
容易确认,也容易搞错。经由同一个代理,对一个快速、中性的端点和你真实的目标,分别给同一条请求路径计时:
# 中性端点 —— 测的是代理开销requests.get("https://api.ipify.org", proxies=proxies, timeout=(10, 30))
# 你真实的目标 —— 测的是代理开销 + 目标延迟requests.get("https://your-target.example/page", proxies=proxies, timeout=(10, 30))如果中性端点很快而目标很慢,那代理不是你的问题,再多的代理调优也修不好它。为那个目标调高读取超时,或者少拉一些页面内容。
原因 4:并发开得太高
那种只在有负载时出现、而你测单个请求时就消失的超时,指向的就是这里。
有两种机制:你可能正在耗尽本地资源(连接池槽位、文件描述符、事件循环容量),于是请求还没出门就在你自己这侧排起了队;或者目标正在对你限流,并且是挂着不动、而不是干脆返回一个 429。
诊断它的办法是把并发降到 1 再测一次。如果超时消失了,那就是负载相关的。修法: 施加按主机的并发上限,而不是一个全局数字,这正是代理负载均衡里的架构。
原因 5:连接处理
两个相反的错误,都会产出超时:
没有连接复用。 每个请求都建一条新连接,意味着每次都要穿过代理付一遍完整的 TCP + TLS 握手,这既慢、也让你的超时余量小得多。用一个带池化的 session/client。
池化连接过期了。 如果你池化了连接、却又按请求轮换出口 IP,那些池化的 socket 可能指向已经失效的出口,而它们会挂住。把池化与一个粘性会话配对,好让池化连接留在一个出口上,并定期回收连接。
原因 6:出口设备本身
住宅出口是真实家庭网络上真实的消费者设备。有些在拥塞的线路上、有些是移动网络、有些会在请求中途掉线。一小部分慢的或失败的请求,在住宅上是正常且应当预期的,不是缺陷。
修法: 不要为了迁就最差的那台设备而调高超时,那只会让每一次失败都变得更慢。快速失败,并用一个新身份重试,那会给你换一个不同的出口。昨天的故障转移指南讲了如何对传输类失败分类并正确重试。池的质量决定了那条尾巴有多厚(IP 信誉)。
原因 7:它根本就没到达代理
如果一切都超时,尤其是在容器里,值得早点检查这一条。
确认请求确实是经由 gateway 出去的:
curl -x customer-USER-country-us:PASS@p.shifter.io:443 https://api.ipify.org# 返回一个住宅 IP -> 代理是通的。# 返回你自己的 IP -> 你的客户端在无视代理。# 完全挂住 -> 本地出站被挡了(防火墙、VPN、企业网络)。在 Docker 和 Kubernetes 里,这是一个常见原因:客户端根本不遵守 HTTP_PROXY、或者 NO_PROXY 配错了、又或者容器里的 localhost 并不是你以为的那个意思。Docker 配置指南专门讲了这些情形。
原因 8:伪装成超时的认证或凭据错误
一个格式错误的用户名(定位标志里的拼写错误、一个不被支持的参数)或错误的凭据,可能会因你的客户端如何处理 407 而表现为挂起或一个笼统的失败。如果你最宽松的配置仍然失败,那就在假定是网络问题之前,逐字符核对凭据串。
诊断顺序
按顺序跑这几步;每一步都能排除掉一大类原因:
- 把 connect 和 read 分开。 连接失败意味着你这侧;读取失败意味着出口或目标。
- 确认你到底有没有走代理(上面那条 ipify 检查)。
- 只用
country测一次。 如果那样能行,说明你的地理过滤太紧了。 - 拿中性端点与你的目标做对比。 把代理开销和目标的慢区分开。
- 把并发降到 1。 如果超时消失,那是负载,不是代理。
- 拿你的超时值对照实测 p95。 如果它更低,那就是你在制造失败。
六项检查,而实践中,其中一项就能解释我们所见的几乎每一份超时报告。
什么时候超时其实是正常的
一小条慢请求和失败请求的尾巴,是住宅代理天生就有的,因为真实的消费者设备天生就有波动。用越来越长的超时去追求 100% 的成功率,是错误的目标,那只会让你的失败变慢,而不会让它变少。
正确的目标是一个 SLO:为你的工作负载定义一个可接受的成功率和 p95,在尾部快速失败,并用一个新鲜身份重试。一条在 30 秒内让请求失败、并在重试时成功的管道,比一条抱着希望等 120 秒的管道更健康。
常见问题
为什么我加了城市或 ASN 过滤会超时,只用 country 却不会? 因为每个标志都会收窄合格的出口池。国家 + 城市 + ASN 可能只剩下极少的匹配 IP,于是请求会等待、然后失败。放宽到你的数据真正需要的那点精度;而当你确实需要紧密定位时,就要预期更低的吞吐。
住宅代理我该用什么超时值? 先测量:你的超时值应当在你观察到的 p95 之上,并留有余量。作为起点,对住宅来说大致 10 秒连接、30 秒以上读取是合理的,然后按你自己的数字来调。按数据中心调的超时值,会把健康的住宅请求砍断。
我怎么判断慢的是代理还是目标? 经由同一个代理,给一个快速的中性端点和你真实的目标分别计时。中性端点测的是代理开销;两者之差就是目标自身的延迟。如果中性端点很快,那代理不是问题。
所有请求都超时,连简单请求也是。哪里出问题了? 先确认你到底有没有触达代理:经由它 curl 一个 IP 回显端点。返回你自己的 IP,说明客户端在无视代理;完全挂住,说明本地出站被挡了(防火墙、VPN、容器配置)。然后核对你的凭据和标志。
我是不是把超时调大就行了? 通常不行。如果原因是过紧的地理过滤、一个慢的目标,或一台差的出口设备,那更长的超时只会让失败花更长时间。去修那个原因;而对于无法避免的那条尾巴,快速失败并用一个新身份重试。
底线
超时是一个至少有八种不同原因的症状,而修法完全取决于你遇到的是哪一种。把 connect 和 read 分开、确认你确实在走代理、放宽地理过滤、把目标的慢与代理开销隔离开、在并发为 1 时测试,并拿你的超时值对照实测 p95。这套顺序能解决绝大多数情形,通常只要几分钟。
并且接受那条尾巴:住宅出口是真实设备,所以一些波动,正是换取真实用户信任所付的代价。快速失败、用新鲜身份重试,并以成功率和 p95 来评判这套配置,而不是以”有没有哪个请求曾经超时”。如果六项检查之后你还是卡住,住宅 gateway 的文档和我们的团队可以帮你缩小范围,带上你的 connect/read 拆分和一个失败凭据串的样本,答案通常很快就能找到。