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

时间:2015-03-06 08:14:13

标签: javascript node.js http request

使用Node.js通过HTTP请求查询某些公共API。因此,我使用request模块。我在我的应用程序中测量响应时间,并看到我的应用程序返回API查询的结果大约比#34;直接"通过curl或浏览器请求。此外,我注意到与启用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);
    }

});

有人看到优化潜力吗?我做错了什么吗?提前感谢任何建议!

2 个答案:

答案 0 :(得分:5)

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

  • 使用request总是比直接使用http慢,因为正如智者曾经说过的那样:“抽象成本”。 ;)实际上,为了挤出每一个可能的性能,我将直接使用节点的net模块处理所有HTTP请求。对于HTTPS,不值得重写https模块。根据定义,由于需要握手加密密钥并对加载有效的加密/解密工作,HTTPS总是比HTTP慢。
  • 如果您的要求包括从任何单个服务器检索多个资源,请确保这些请求是按顺序进行的,并设置了http KeepAlive,以便您可以从已打开的套接字中受益。与在已经打开的套接字上发出请求相比,握手新TCP套接字所花费的时间是 huge
  • 确保禁用http连接池(请参阅Nodejs Max Socket Pooling Settings
  • 确保您的操作系统和shell不限制可用套接字的数量。有关提示,请参阅How many socket connections possible?
  • 如果你正在使用linux,请检查Increasing the maximum number of tcp/ip connections in linux,我也强烈建议微调内核套接字缓冲区。

我会在发生时添加更多建议。

更新

有关对同一端点的多个请求主题的更多信息:

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

TCP握手分为三个阶段。

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

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

从我的桌面,到www.google.com的2K八位字节数据包的当前延迟(通过ping测量的往返时间)在37到227毫秒之间。

因此,假设我们可以依赖95ms的往返平均值(通过完美连接),初始TCP握手的时间将是大约130ms或SYN(45ms)+ SYN + ACK(45ms)+ ACK( 45ms)这是建立初始连接的十分之一秒。

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

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

为了改善这一点,我让你的工作人员保持与“已知”目的地的开放连接池,然后他们将广告回到管理员进程,以便它可以通过“实时”连接将请求定向到负载最小的服务器到目标服务器。

答案 1 :(得分:3)

实际上,我有一些新的元素足以打开真正的答案。看看request uses the HTTP agent的方式,请尝试以下方法:

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

这将禁用连接池,并且应该更快。