Python3 HTTP请求在服务器端耗时过长的排查问询
看起来你碰到了一个很典型的"本地正常、服务器异常"的网络问题,而且固定的2分10秒这个线索非常关键——这种固定时长一般和超时重试、网络链路阻塞或者目标站点的反制策略有关。先把你的场景再理一遍:
你用requests发起HTTP请求的代码如下:
import requests response = requests.get("http://example.com/foo/bar/", headers={"User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36"})
本地运行秒级响应,但部署到服务器后每次都耗时恰好2分10秒,开启了全量的urllib3和requests日志后,只看到两个关键日志:
2018-05-31 19:55:56,894 - urllib3.connectionpool - DEBUG - Starting new HTTP connection (1): example.com 2018-05-31 19:58:06,676 - urllib3.connectionpool - DEBUG - http://example.com:80 "GET /foo/bar/ HTTP/1.1" 200 None
从时间差能看出来,从发起连接到收到响应的间隔刚好是2分10秒,下面是具体的排查步骤,按优先级排序:
1. 先排查DNS解析是否拖慢了速度
urllib3打印"Starting new HTTP connection"日志前,其实已经完成了DNS解析步骤。可以在服务器上手动测试DNS解析耗时:
# 用nslookup测试基础解析耗时 time nslookup example.com # 用dig测试,能看到更详细的解析过程 time dig example.com
如果解析耗时接近2分10秒,那问题就出在DNS上——可能服务器配置的DNS服务器响应慢、超时,或者存在DNS缓存失效的情况,建议更换可靠的DNS服务器(比如公共DNS 8.8.8.8)试试。
2. 用抓包工具看TCP连接阶段的问题
固定时长很可能是TCP三次握手阶段的重试超时。在服务器上用tcpdump抓包,观察请求的SYN包和ACK包的时间差:
tcpdump host example.com and port 80 -tttt
如果看到SYN包发出去后,过了很久才收到ACK,甚至有多次SYN重传,那说明服务器到目标站点的网络链路有问题——比如中间的防火墙丢包、运营商线路故障,导致TCP连接重试多次才成功,累加的重试时间刚好是2分10秒。
3. 验证目标站点是否对服务器IP做了延迟限制
本地请求正常,服务器请求被延迟,大概率是目标站点识别到你的服务器IP属于云服务商集群,触发了反爬的延迟响应机制(不是直接拒绝,而是让你等一段时间再返回内容)。可以在服务器上用curl模拟完全相同的请求:
curl -A "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" http://example.com/foo/bar/ -w "\nTotal time taken: %{time_total}s\n"
如果curl的耗时也是2分10秒,那基本可以确定是目标站点的限制。可以尝试:
- 添加更多真实浏览器的请求头(比如
Accept、Accept-Language、Referer等) - 使用代理IP请求
- 联系目标站点的管理员解除限制
4. 检查服务器的代理和防火墙设置
服务器可能配置了全局HTTP/HTTPS代理,而代理服务器本身响应缓慢;或者服务器的防火墙、安全组规则限制了对外的HTTP请求,导致请求被拦截后重试。可以:
- 检查服务器的环境变量,看看是否有
http_proxy、https_proxy设置:echo $http_proxy echo $https_proxy - 联系运维确认服务器的安全组、防火墙是否允许访问目标站点的80端口
5. 测试requests的超时配置,排除重试机制的影响
虽然你的代码没有显式设置超时,但urllib3(requests的底层库)默认有重试策略。可以手动给requests添加超时参数,看看会不会改变时长:
response = requests.get("http://example.com/foo/bar/", headers=..., timeout=10)
如果设置10秒超时后,请求直接抛出超时异常,那说明之前的2分10秒是urllib3默认的重试累加时间,需要检查服务器上是否有全局的urllib3重试配置。
6. 用路由追踪工具排查网络链路瓶颈
用traceroute或mtr工具查看服务器到目标站点的路由情况,定位是否有中间节点延迟过高或丢包:
# traceroute查看路由路径 traceroute example.com # mtr结合traceroute和ping,更直观展示链路状态 mtr example.com
如果某个节点的丢包率很高或者延迟超过几秒,那问题就出在这个链路节点上,需要联系运营商或者云服务商解决。
内容的提问来源于stack exchange,提问作者morgoth84

