node发出的请求数多了,整体响应变慢,不清处影响的因素是什么,求解惑。
发布于 10 个月前 作者 THROFHR 3079 次浏览 最后一次编辑是 9 个月前 来自 问答

大概是这样的,我有个需求,需要向某个api 不断的请求,而且数量不小,有点像压力测试吧

const fetch = require('node-fetch');
const funs = async () => {
  const now = Date.now();
  await fetch('https://www.baidu.com/');
 console.log(i, `start:${now}`, `end:${Date.now()}`, `use:${Date.now() - now}`);
};

在我的机器上跑,发现 同时跑 10、100、1000得到的结果时间相差太多

 for (let i = 0; i < 10; i += 1) {
   funs(i);
 }
 // funs log的时间大概是 80-100ms 递增
 
 for (let i = 0; i < 100; i += 1) {
   funs(i);
 }
 // funs log的时间大概是 500-800ms 递增
 
 for (let i = 0; i < 1000; i += 1) {
   funs(i);
 }
 // funs log的时间大概是 1000-5000ms 递增
部分评论的尝试
//01,尝试设置maxSockets 
https.globalAgent.maxSockets = 1000;
https.globalAgent.maxFreeSockets = 1000;
//02,用原生https尝试设置new Agent  
const https = require('https');
const $get = (i) => {
  const now = Date.now();
  const agent = new https.Agent();
  const options = {
    hostname: 'www.baidu.com',
    port: 443,
    method: 'GET',
    agent: false, // agent
  };
  https.get(options, () => {
    console.log(i, `start:${now}`, `end:${Date.now()}`, `use:${Date.now() - now}`);
  }).on('error', () => {
    console.log(i, `start:${now}`, `end:${Date.now()}`, `use:${Date.now() - now}`);
  });
};

for (let i = 0; i < 1000; i += 1) {
  $get(i);
}
//结果还是没变化
不明白造成请求的时间变长的具体原因是啥?

瞎猜1 node有类似浏览器一样有请求数限制?

瞎猜2 TCP链接数限制?

希望能解决: 10000并发以内不会出现大幅度延迟

有没有大佬帮忙解惑?

33 回复

要等for循环结束后才处理response。循环次数越大当然log时间就越长。 你试试循环个十万……

@waitingsong for循环里面是异步的,for循环1000 结束时间用了650ms,10w没试出来,1w的话循环时间大概是6412ms,响应时间从5s 逐渐增加 到 40s。 log出来的时间也是从某个请求发出开始到结束的,应该和for循环没关系。 大佬,还有其他分析建议吗?

lz 你同时把 now 值打印出来瞧瞧

@waitingsong 时间now是函数内的时间,我看了,没有问题,太长我就不粘贴出来了,for 循环1000里面 某一次前10条

132 'start:1532618207904   end:1532618208595  use:691'
764 'start:1532618208348   end:1532618208927  use:579'
857 'start:1532618208413   end:1532618208988  use:575'
889 'start:1532618208454   end:1532618209079  use:625'
9 'start:1532618207826   end:1532618209484  use:1658'
15 'start:1532618207829   end:1532618209494  use:1665'
5 'start:1532618207825   end:1532618209496  use:1671'
16 'start:1532618207829   end:1532618209496  use:1667'
10 'start:1532618207827   end:1532618209497  use:1670'
39 'start:1532618207839   end:1532618209502  use:1663'

你得关注下 node-fetch 具体是怎么实现得

@THROFHR 为啥不前后各取几条然后比较下 start 差异呢。然后再瞧瞧第一条的end和最后一条的start

这种情况用golang的gorutine吧,如果不会就是用队列,用process.nextTick每次请求几百个,如果嫌队列不够效率,就用cluster-worker多进程的模式并行处理吧 慢的原因主要在于远程网络访问及对方应用的并发响应效率

@JacksonTian 源码我看过了,没有做啥特殊处理,默认的http 或 https 的 agent.maxSockets都是 Infinity,不过刚刚发现 agent 里面有个 maxFreeSockets 默认为256 ,不知是不是受它影响,正在验证中…

@waitingsong 第一条没有可比性啊,要比是最后一条,10,100,1000的最后一条start时间相差不过600ms,但是10和1000的end时间相差40s+

@phper-chen 不用go的原因是应为这不是写压力测试,另外一个是对go不熟悉,因为要结合一下业务需求,感觉写sh脚步调用也不合理。 cluster-worke的话没试过,谢谢你的建议,我去尝试一下。 最后一个关于:慢的原因主要在于远程网络访问及对方应用的并发响应效率,我感觉应该不是,我对那个测试API,然后我看到响应时间平均都是500ms左右。带宽应该也不是问题,远端测试跑的是linode ,我本地网络上行也有20MB/S 下行100MB/S

你在机器上看下端口数是否上涨?是否开启http连接复用

使用长连接,别每次都是新建连接,用过superagent的长连接

来自酷炫的 CNodeMD

@luyufa 不太懂你说的 QAQ,怎么看端口是否上涨,是否开启http连接复用是指设置 keep-alive吗?

@MedusaLeee 长链接需要服务器配合吧?

内部调用用 rpc,类似于echo双向的这种,假如是请求,大规模的话建议单独弄一台机器,或集群发送请求,通过 rpc 接受结果。 浏览器开多了网页也卡啊。

并发其实 erlang 不错。

@MiYogurt 集群是最后的方法,但我感觉单机是能处理的。我用的是Linode 4G的一个节点,即是并发发出1w的请求,网络和IO都不应该存在瓶颈,应该是哪的默认配置限制的。

@THROFHR 嗯,http1.1默认开启keep alive

来自酷炫的 CNodeMD

@THROFHR 我曾经遇到过node使用request发请求越来越慢 是因为request需要使用httpAgent开启代理来进行连接复用,感觉你这个很像。端口的话不记得了自己百度就一个命令

@luyufa 我设置了Agen keep-alive为true 确实快了很多,但感觉还是无法满足我的使用场景。

是不是系统fd数量的限制?执行 ulimit -n看看

@royalrover 应该不是 ulimit -n 显示 1048576 感觉已经够大了

有没有看 调的api同时并发请求 会变慢 只是猜想

建议你直接使用原生http模块请求下对比测试,http也不要使用agent,很好奇导致这个情况的原因。

@weizhuanhua 没有读懂你的表达…

@royalrover 试过了,结果也是一样,最后还是没找出问题所在

http://fibjs.org/docs/guide/about.md.html 看“拥抱高能”那段 估计应该是async的问题导致的,你试试用其他异步方式会不会变快?

Node的Http模块封装了TCP,底层会复用TCP连接,这个时候会有一个全局的Agent代理,这个代理对同一域名的请求并发为5,超过这个数字的请求会被放到等待队列里。 如果想要扩大这个并发请求数,要么是自己定义一个agent将maxSockets设置为一个更大的数字,要么是直接就把Http的option设置为agent:false。

为了验证这个问题,你可以把你的agent打印出来看看,里边会有sockets和requests,分别表示并发数和等待的请求数,要是requests数量较大,说明就是这个原因。

如果你这些请求没有严格的前后顺序的话,应该用Promise.all将所有请求放到一起进行请求,然后再await

来自酷炫的 CNodeMD

@tinycold 应该不是这里,nodejs http现在默认是maxSockets: Infinity,我打印出来看了一下 maxSockets: Infinity, maxFreeSockets: 256, maxCachedSessions: 100, 之前也尝试了设置 maxSockets ,maxFreeSockets 10000,没有效果

@hwj128911 时间还是一样长

@suyuanhan 没有肉眼可见的变化,直接用cb的方式

回到顶部