73

我们有一个 node.js 服务器,它实现了一个 REST API 作为中央服务器的代理,它有一个稍微不同的,不幸的是不对称的 REST API。

我们的客户端在各种浏览器中运行,它要求节点服务器从中央服务器获取任务。节点服务器从中央服务器获取所有任务 ID 的列表并将它们返回给客户端。然后,客户端通过代理对每个 id 进行两次 REST API 调用。

据我所知,这些东西都是异步完成的。在控制台日志中,当我启动客户端时,它看起来像这样:

Requested GET URL under /api/v1/tasks/*: /api/v1/tasks/

这需要几秒钟才能从中央服务器获取列表。一旦它得到响应,服务器很快就会把它吐出来:

Requested GET URL under /api/v1/tasks/id/:id :/api/v1/tasks/id/438
Requested GET URL under /api/v1/workflow/id/:id :/api/v1/workflow/id/438
Requested GET URL under /api/v1/tasks/id/:id :/api/v1/tasks/id/439
Requested GET URL under /api/v1/workflow/id/:id :/api/v1/workflow/id/439
Requested GET URL under /api/v1/tasks/id/:id :/api/v1/tasks/id/441
Requested GET URL under /api/v1/workflow/id/:id :/api/v1/workflow/id/441

然后,每次这些请求中的一对从中央服务器获得结果时,另外两行很快就会被吐出。

所以看起来我们的 node.js 服务器一次只愿意发出六个请求。

4

6 回答 6

164

Node 本身没有 TCP 连接限制。(重点在于它是高度并发的,可以同时处理数千个连接。)您的操作系统可能会限制 TCP 连接。

更有可能您遇到了后端服务器的某种限制,或者您遇到了内置 HTTP 库的连接限制,但是如果没有有关该服务器或您的 Node 实现的更多详细信息,很难说。

Node 的内置HTTP 库(显然是任何构建在它之上的库,大多数)维护一个连接池(通过Agent类),以便它可以利用 HTTP 保持活动。当您对同一服务器运行许多请求时,这有助于提高性能:而不是打开 TCP 连接、发出 HTTP 请求、获得响应、关闭 TCP 连接并重复;可以在重用的 TCP 连接上发出新请求。

在节点 0.10 和更早版本中,HTTP 代理默认只会打开 5 个同时连接到单个主机的连接。您可以轻松更改:(假设您已将requireHTTP 模块设置为http

http.globalAgent.maxSockets = 20; // or whatever

节点0.12将默认设置maxSocketsInfinity.

您可能希望保持某种连接限制。您不想在一秒钟内用数百个 HTTP 请求完全压倒您的后端服务器 - 性能很可能比让代理的连接池做它的事情,限制请求以免使您的服务器过载。您最好的选择是进行一些实验,看看在您的情况下并发请求的最佳数量是多少。

但是,如果您真的不想要连接池,您可以完全绕过池 -在请求选项中发送agent到:false

http.get({host:'localhost', port:80, path:'/', agent:false}, callback);

在这种情况下,并发 HTTP 请求绝对没有限制。

于 2012-08-21T18:37:50.613 回答
16

这是浏览器中并发连接数的限制:

流行的浏览器允许多少并发 AJAX (XmlHttpRequest) 请求?

我赞成其他答案,因为它们帮助我诊断了问题。线索是节点的套接字限制是 5,而我一次得到 6 个。6 是 Chrome 中的限制,这是我用来测试服务器的。

于 2012-08-21T19:24:19.073 回答
8

您如何从中央服务器获取数据?http使用模块发出 HTTP 请求时,“节点不限制连接”并不完全准确。以这种方式发出的客户端请求使用 的http.globalAgent实例http.Agent,并且每个请求http.Agent都有一个调用设置,该设置maxSockets确定代理可以向任何给定主机打开多少个套接字;这默认为 5。

因此,如果您使用http.requestor http.get(或依赖于这些方法的库)从中央服务器获取数据,您可以尝试更改 的值(或在您使用http.globalAgent.maxSockets的任何实例上修改该设置)。http.Agent

看:

于 2012-08-21T20:53:13.553 回答
3

Node js 可以处理数以千计的传入请求——是的!

但是,当涉及到 ougoing 请求时,每个请求都必须处理 dns 查找和 dns 查找、磁盘读取等由用 C++ 编程的 libuv 处理。每个节点进程的线程默认值为 4x 线程。

如果所有 4x 线程都忙于 https 请求(dns 查找),其他请求将被排队。这就是为什么无论您的代码多么出色:有时每秒完成的并发传出请求数为 6 或有时更少。

了解 dns 缓存以减少 dns 查找量并增加 libuv 大小。如果您使用 PM2 来管理您的节点进程,他们确实有关于环境变量以及如何注入它们的良好文档。您正在寻找的是环境变量 UV_THREADPOOL_SIZE = 4

您可以将值设置为 1 或最大限制 1024 之间的任何值。但请记住,libuv 限制为 1024 是跨所有事件循环的。

于 2020-07-15T16:34:09.003 回答
2

我在我的服务器上看到了同样的问题。它只处理 4 个请求。正如已经从 0.12 开始解释的那样,maxsockets 默认为无穷大。这很容易使服务器不堪重负。将请求限制为 10

http.globalAgent.maxSockets = 20;

解决了我的问题。

于 2017-04-05T03:59:56.497 回答
1

您确定它只是将结果返回给客户端吗?Node 在一个线程中处理所有内容。因此,如果您进行一些花哨的响应解析或其他任何无法产生的事情,那么它会阻止您的所有请求。

于 2012-08-21T18:51:14.113 回答