【问题标题】:Sockets don't appear to be closing when using Node.js http.get使用 Node.js http.get 时,套接字似乎没有关闭
【发布时间】:2014-07-01 19:54:39
【问题描述】:

OS X 10.8.3

节点 0.10.0

我正在使用“http”模块向 Facebook 图形 API 发出请求。

以下是我传递给“http.get”的选项:

var options = {host: 'graph.facebook.com',
               port: 80,
               path: '/' + fb_id + '/picture'};  //fb_id is a Facebook user identifier

我的代码如下所示:

http.get(options,
  function(res) {
    ...some stuff...
    DONE(RESULT);  //DONE is a callback function
  }).on('error', function(e) {
       ...some error handling...
});

我观察到的是,我只能执行与 http.globalAgent.maxSockets 的值一样多的请求。一旦我达到这么多请求,对 http.get 的下一次调用就永远不会(显然)连接。我已经确认我没有收到请求错误。

就好像响应进来后套接字没有被关闭。

作为响应处理程序的一部分,我需要做些什么来确保套接字已关闭?

这些套接字是否因为默认的保活行为而没有关闭?

我应该如何进行调试?

【问题讨论】:

    标签: node.js sockets http


    【解决方案1】:

    尝试在选项中设置agent: false。默认行为确实是为 HTTP keep-alive 保持连接打开:

    var options = {host: 'graph.facebook.com',
                   port: 80,
                   path: '/' + fb_id + '/picture',
                   agent: false};
    

    【讨论】:

    • 我在文档中看到了这一点,但发现它令人困惑:“如果没有挂起的 HTTP 请求正在等待套接字变得空闲,则套接字将关闭。这意味着节点的池具有保持活动的好处在负载下但仍不需要开发人员使用 keep-alive 手动关闭 HTTP 客户端。”我不明白为什么汇集的、已经打开的连接不用于后续请求。我会尝试agent: false,并期待它的好东西。
    • 我认为http 模块不会对池中没有可用套接字的任何请求进行排队。如果达到maxSockets 并且所有这些请求仍处于待处理状态,则任何后续请求都无法从池中获得空闲套接字,只会被丢弃。
    • 我意识到我的应用程序架构导致了我的问题,因为我在每次请求之前都重新要求了“http”模块,这意味着每个 http 引用都是独立的。我试图改变这一点,以便在“get”调用之间共享 http 模块引用,但我看到了相同的行为(第一个 globalAgent.maxSockets 请求很好,其余的因缺少套接字而挂起)。这就引出了一个问题——如何利用这种默认的保活行为?
    • 罗伯特,您的评论是有道理的,但我知道这些响应已成功收到,我认为这意味着相关的请求尚未挂起。我将整个“keepalive”默认行为的意思是“http 模块将允许同一个套接字上的多个 get 请求而无需关闭/重新打开它”。对吗?
    • @GeniaS。节点进程是独立的,它们之间没有共享套接字池或任何东西。从节点 0.12 开始,maxSockets 设置为Infinity,因此显然之前的(0.12 之前的)限制(我相信是 5)被认为过于严格。在某些时候,如果有数千个并发连接到远程 HTTP 服务器,您遇到问题,但是最好在代码中明确地限制并发请求的数量,而不是通过一些硬编码的默认值.
    【解决方案2】:

    Node 的 http 模块声明代理默认为全局代理:http://nodejs.org/api/http.html#http_http_globalagent,这意味着无论发起请求的模块是什么,都会共享 keep-alive。

    顺便说一句,在 2013 年 4 月 9 日 20:47 回复 Wes 的评论:加载节点模块的次数无关紧要,它只会加载一次并由所有模块共享。

    您遇到的是池耗尽问题。避免它的最简单方法是使用具有所需 maxSockets 的新代理 (http://nodejs.org/api/http.html#http_class_http_agent)。请记住,如果您将创建的代理放在该模块的导出中(节点中的模块是有状态的!!!),则可以在模块之间共享它。

    【讨论】:

      【解决方案3】:

      我遇到了相同的行为,只是我的连接最终在超时后被重用。检查连接是否在一段时间(几分钟)后被重用,并检查响应标头是否包含“连接:保持活动”。

      如果是这种情况,一个可能的解决方案是使用“连接:关闭”标头而不是保持活动状态,这样就可以像通常的设置一样更早地重用池连接。我不确定这是否会导致使用 facebook 端点出现任何性能问题。

      var options = {host: 'graph.facebook.com',
                     port: 80,
                     path: '/' + fb_id + '/picture',
                     headers: { 'Connection':'Close' }
      };
      

      对我来说,使用 agent:false 不起作用,因为我发送的大量请求耗尽了服务器资源。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2020-11-17
        • 2017-01-26
        • 2014-07-09
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多