与浏览器相比,通过Node.js延迟了HTTP请求

在使用Node.js通过HTTP请求查询一些公共API。 因此,我正在使用request模块。 我正在测量我的应用程序中的响应时间,并且看到我的应用程序通过curl或浏览器从API查询中返回比“直接”请求慢2-3倍的结果。 另外,我注意到与启用了HTTPS的服务的连接通常比普通HTTP服务的连接时间要长,但这可能是巧合。

我试图优化我的request选项,但无济于事。 例如,我查询

https://www.linkedin.com/countserv/count/share?url=http%3A%2F%2Fwww.google.com%2F&lang=en_US

我使用request.defaults来设置所有请求的整体默认值:

 var baseRequest = request.defaults({ pool: {maxSockets: Infinity}, jar: true, json: true, timeout: 5000, gzip: true, headers: { 'Content-Type': 'application/json' } }); 

实际的请求是通过

 ... var start = new Date().getTime(); var options = { url: 'https://www.linkedin.com/countserv/count/share?url=http%3A%2F%2Fwww.google.com%2F&lang=en_US', method: 'GET' }; baseRequest(options, function(error, response, body) { if (error) { console.log(error); } else { console.log((new Date().getTime()-start) + ": " + response.statusCode); } }); 

有没有人看到优化的潜力? 我在做什么完全错误的? 在此先感谢您的任何build议!

根据您对架构的理解,您需要解决几个潜在的问题。 他们没有特定的顺序:

  • 正如智者所说:“抽象成本”,使用request总是比直接使用http要慢。 ;)事实上,为了挤出每一个可能的性能,我会直接使用节点的net模块来处理所有的HTTP请求。 对于HTTPS,不值得重写https模块。 而为了logging,由于需要握手encryption密钥并且对有效载荷进行encryption/解密工作,所以根据定义,HTTPS总是比HTTP慢。
  • 如果您的要求包括从任何一台服务器检索多个资源,请确保这些请求是通过http KeepAlive设置的,以便您可以从已经打开的套接字中受益。 与在已经打开的套接字上发出请求相比,握手一个新的TCP套接字花费的时间是巨大的
  • 确保http连接池被禁用(请参阅节点最大套接字池设置 )
  • 确保您的操作系统和shell不限制可用套接字的数量。 请参阅可能有多less套接字连接? 提示。
  • 如果你正在使用linux,请检查在linux中增加最大数量的tcp / ip连接 ,我也强烈build议微调内核套接字缓冲区。

我会添加更多的build议,因为他们发生在我身上。

更新

更多关于对同一端点的多个请求的主题:

如果您需要从同一端点检索大量资源,将您的请求分段到与该端点保持开放连接的特定工作人员将很有用。 通过这种方式,您可以放心,您可以尽快获得请求的资源,而不会受到初始TCP握手的开销。

TCP握手是一个三阶段的过程。

第一步:客户端向远程服务器发送SYN数据包。 第二步:远程服务器用SYN + ACK回复客户端。 第三步:客户端用ACK回复远程服务器。

根据客户端到远程服务器的延迟,这可以加起来(正如William Proxmire曾经说过的)“真钱”,或者在这种情况下,延迟。

从我的桌面上,到www.google.com的2K字节数据包的当前延迟(ping的往返时间测量)是37到227ms之间的任何地方。

假设我们可以依靠95ms的往返时间(通过一个完美的连接),初始TCP握手的时间约为130ms或SYN(45ms)+ SYN + ACK(45ms)+ ACK(45ms)这是build立初始连接的十分之一秒。

如果连接需要重新传输,则可能需要更长的时间。

假设您通过新的TCP连接检索单个资源。

为了改善这一点,我希望你的工作人员保持与“已知”目的地的开放连接池,然后他们将这些目标通知给主pipe进程,以便能够通过到目标的“实时”连接将请求引导到装载最less的服务器服务器。

其实,我有一些新的元素足以打开一个真实的答案。 查看request 使用HTTP代理的方式,可以请尝试以下操作:

 var baseRequest = request.defaults({ pool: false, agent: false, jar: true, json: true, timeout: 5000, gzip: true, headers: { 'Content-Type': 'application/json' } }); 

这将禁用连接池,并应使其快得多。