1Gbps网络下JS并发请求脚本最高仅占用80Mbps带宽问题排查
问题描述
我使用60个HTTP代理在JS中发起200个并发GET请求,每个请求下载1.6MB的文件,代理延迟为300-400ms。网络下行速率通常为1000Mbps到1500Mbps,脚本运行在Windows Server上,此前Ookla测速结果符合带宽标称值。
相关代码如下:
async function sendRequest(kw, anchor, proxy, cb) { const [ip, port, user, pass] = proxy.split(':') var url = /*some api endpoint*/ var options = { headers: { 'accept': "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9", 'accept-language': "en-US,en;q=0.9,fr;q=0.8", 'cache-control': "max-age=0", 'if-none-match': "W/\"701c0-GT5kESYD+JEYlkRTfHGT3PH+PTI\"", 'sec-ch-ua': "\"Google Chrome\";v=\"89\", \"Chromium\";v=\"89\", \";Not A Brand\";v=\"99\"", 'sec-ch-ua-mobile': "?0", 'sec-fetch-dest': "document", 'sec-fetch-mode': "navigate", 'sec-fetch-site': "none", 'sec-fetch-user': "?1", 'upgrade-insecure-requests': "1" }, proxy: { host: ip, port: port, auth: { username: user, password: pass } } } axios.get(url, options).then(res => cb(res)) } let proxies = [/*proxies go here*/] let kws = [/*keywords go here*/] let responses = [] let starttime let finishtime function sendRequests(limit) { if (limit > kws.length) return console.log('limit exceeds request kws') for(let i = 0; i < limit; i++) { console.log('sending request......') sendRequest(kws[i], '50', proxies[i], function (res) { console.log('status: '+res.status) responses.push(res) if(responses.length == limit) { finishtime = returnTimeMilliseconds() console.log('Finished '+limit+' requests in ' + (finishtime - starttime)/1000 + ' seconds') } }) } } function returnTimeMilliseconds() { var d = new Date(); return d.getTime() } starttime = returnTimeMilliseconds() sendRequests(200)
单个请求平均耗时1.5-2秒,并发数不超过5时,从所有请求发起到最后一个请求返回总耗时仍为1.5-2秒,符合并发的定义。但当并发数提升到10、20或200时,首个请求的返回耗时通常长达5到10秒,所有请求处理完成的速率约为每秒5个。
通过Windows资源监视器监测,脚本运行期间网络占用最高仅为80Mbps。
我曾在两个不同的WiFi网络下运行该脚本:第一个是30Mbps带宽的网络,虽然耗时更长,但30Mbps带宽被完全占满,实际速率约为3.45MBps。当前网络的理论下载速率应为125到187.5MBps,但实际速率远低于该值,请问该问题可能的原因是什么?
原因分析
- 代理资源不足与代理端限制:你仅有60个可用代理,却一次性发起200个并发请求,超出代理数量的请求会直接进入排队状态等待空闲代理。此外绝大多数商用代理对单代理的并发请求数、单位时间请求量都有严格限制,通常单代理同时承载1-3个请求就会触发限速或队列,你实际可用的并发通道远小于60,大量请求堵在代理排队环节,直接拉低整体效率,甚至拖慢首个请求的响应速度。
- Node.js与axios的默认连接限制:axios底层调用Node.js原生的http/https模块,默认全局最大套接字数仅有几十个,你没有在代码中自定义配置httpAgent/httpsAgent的maxSockets参数,高并发下大量请求会卡在套接字分配阶段,无法及时发出。
- Windows系统与WiFi连接的瓶颈:Windows Server默认对出站TCP连接数、半开连接数、临时端口范围都有严格的默认限制,高并发场景下容易出现端口耗尽、连接排队的问题。且你使用WiFi连接网络,Windows的WiFi网卡驱动和TCP栈对高频出站连接的处理效率远低于有线以太网卡,即使带宽足够,连接建立阶段的开销也会被大幅放大。
- 代理出口带宽限制:你单请求需要下载1.6MB文件,按单请求耗时1.5s计算,60个代理即使每个同时只跑1个请求,总瞬时流量已经接近512Mbps,多数代理供应商的出口带宽有限,高并发下会主动丢包或者限速,反而比低并发时的总吞吐量更低。
- 并发逻辑设计不合理:你直接通过for循环一次性发起200个请求,没有做合理的并发池控制,所有请求同时抢占系统资源、代理资源,会触发大量TCP重传、代理重试,整体效率不升反降。
内容的提问来源于stack exchange,提问作者Rahul U.
相关产品推荐
相关产品推荐

