大概是这样的,我有个需求,需要向某个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并发以内不会出现大幅度延迟
有没有大佬帮忙解惑?
要等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 我曾经遇到过node使用request发请求越来越慢 是因为request需要使用httpAgent开启代理来进行连接复用,感觉你这个很像。端口的话不记得了自己百度就一个命令
@phper-chen 谢谢
@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的方式