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

Tob*_*obi 12 javascript http request node.js

使用Node.js通过HTTP请求查询某些公共API.因此,我正在使用该request模块.我正在测量我的应用程序中的响应时间,并看到我的应用程序从API查询返回的结果比通过curl或浏览器中的"直接"请求慢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'
    }
});
Run Code Online (Sandbox Code Playgroud)

实际请求是通过

...
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);
    }

});
Run Code Online (Sandbox Code Playgroud)

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

Rob*_*sch 9

根据我对您的体系结构的了解,您需要解决几个潜在的问题。按以下顺序,它们是:

  • 使用request总是比http直接使用要慢,因为正如聪明人曾经说过的:“抽象成本”。;)实际上,为了充分发挥性能,我将net直接使用node的模块处理所有HTTP请求。对于HTTPS,不值得重写https模块。从记录上看,由于需要握手加密密钥并在有效负载上执行加密/解密工作,因此HTTPS在定义上总是比HTTP慢。
  • 如果您的要求包括从任何一台服务器中检索多个资源,请确保已按http KeepAlive设置顺序进行了这些请求,以便可以从已经打开的套接字中受益。与在一个已经打开的套接字上进行请求相比,握手一个新的TCP套接字所花费的时间是巨大的
  • 确保禁用了HTTP连接池(请参阅Nodejs最大套接字池设置
  • 确保您的操作系统和外壳程序不限制可用套接字的数量。请参阅可能有多少个套接字连接?提示。
  • 如果您使用的是Linux,请选中“ 增加 Linux 中tcp / ip连接的最大数量”,我也强烈建议您微调内核套接字缓冲区。

我会在我想到时添加更多建议。

更新资料

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

如果您需要从同一终结点检索大量资源,将您的请求分段到维护与该终结点的开放连接的特定工作人员将很有用。这样,可以确保可以尽快获得请求的资源,而不会产生初始TCP握手的开销。

TCP握手过程分为三个阶段。

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

根据客户端到远程服务器的延迟,这可能总计为(如William Proxmire所说的)“真钱”,或者在这种情况下为延迟。

在我的桌面上,当前2K八位位组数据包到www.google.com的延迟(通过ping来衡量往返时间)在37到227ms之间。

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

如果连接需要重传,它可能需要长时间。

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

为了改善这一点,我希望您的工作人员保留到“已知”目标的开放连接池,然后将它们通告给主管进程,以便它可以将请求定向到负载最小的服务器,并与目标建立“实时”连接服务器。


Tri*_*eur 5

实际上,我有一些新元素足以打开一个真正的答案。看一下request HTTP代理的使用方式您可以尝试以下方法:

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

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