Javascript NodeJS(libuv)kqueue():系统中打开的文件太多

Javascript NodeJS(libuv)kqueue():系统中打开的文件太多,javascript,node.js,Javascript,Node.js,我正在尝试使用node的net模块实现一个简单的HTTP服务器。当我使用庞巴迪(bombardier)测试吞吐量时,节点的HTTP模块处理每个连接都没有问题,但是net模块立即失败。我的问题是,节点的http如何处理新连接或连接池?例如: consthttp=require(“http”); http .createServer((\uRes)=>{ res.end(); }) .听(4000); const net=require(“net”); 网 .createServer((套接字)=

我正在尝试使用node的
net
模块实现一个简单的HTTP服务器。当我使用庞巴迪(bombardier)测试吞吐量时,节点的HTTP模块处理每个连接都没有问题,但是
net
模块立即失败。我的问题是,节点的
http
如何处理新连接或连接池?例如:

consthttp=require(“http”);
http
.createServer((\uRes)=>{
res.end();
})
.听(4000);
const net=require(“net”);
网
.createServer((套接字)=>{
socket.end(“HTTP/1.0 200正常\r\n\r\n”);
})
.听(4000);
然后我运行
庞巴迪-c126-n1000000http://localhost:4000
http
运行良好,但
net
抛出:

(libuv) kqueue(): Too many open files in system
node:tty:94
    throw new ERR_TTY_INIT_FAILED(ctx);
    ^

SystemError [ERR_TTY_INIT_FAILED]: TTY initialization failed: uv_tty_init returned ENFILE (file table overflow)
    at new SystemError (node:internal/errors:251:5)
    at new NodeError (node:internal/errors:336:7)
    at new WriteStream (node:tty:94:11)
    at createWritableStdioStream (node:internal/bootstrap/switches/is_main_thread:47:16)
    at process.getStderr [as stderr] (node:internal/bootstrap/switches/is_main_thread:134:12)
    at console.get (node:internal/console/constructor:216:44)
    at console.value (node:internal/console/constructor:333:50)
    at console.warn (node:internal/console/constructor:368:61)
    at Server.<anonymous> (/Users/brielov/Work/Self/speedtest/net.js:8:37)
    at Server.emit (node:events:365:28) {
  code: 'ERR_TTY_INIT_FAILED',
  info: {
    errno: -23,
    code: 'ENFILE',
    me⏎

(libuv)kqueue():系统中打开的文件太多
节点:tty:94
抛出新错误初始化失败(ctx);
^
SystemError[ERR_TTY_INIT_失败]:TTY初始化失败:uv_TTY_INIT返回ENFILE(文件表溢出)
新系统错误时(节点:内部/错误:251:5)
在新节点错误(节点:内部/错误:336:7)
在新的WriteStream(节点:tty:94:11)
在CreateWriteablestDioStream(节点:内部/bootstrap/switches/is_主线程:47:16)
at process.getStderr[作为stderr](节点:内部/引导/开关/is_主线程:134:12)
在console.get(节点:internal/console/constructor:216:44)
at console.value(节点:内部/控制台/构造函数:333:50)
at console.warn(节点:内部/控制台/构造函数:368:61)
在服务器上。(/Users/brielov/Work/Self/speedtest/net.js:8:37)
在Server.emit(节点:事件:365:28){
代码:“ERR_TTY_INIT_失败”,
信息:{
errno:-23,
代码:“ENFILE”,
我⏎
的概念是,它实现了一个连接池。如果不指定它,则会得到全局默认代理()

在更低级的中,您需要自己管理套接字。在您的示例中,避免套接字耗尽的一种方法是在请求完成后销毁套接字:

const net = require("net");

net
  .createServer((socket) => {
    socket.end("HTTP/1.0 200 OK\r\n\r\n");
    socket.destroy();
  })
  .listen(4000);
请注意,从性能角度来看,始终调用destroy可能不是最佳选择。重用连接和实现池是一个好主意。但为了理解原始实现为什么会快速耗尽资源,缺少destroy调用应该是原因。其他在更高抽象上运行的库将执行在引擎盖下安装该功能


另一种处理超出系统套接字限制的方法是,通过覆盖来限制
net
模块内的连接。不建议仅依赖该功能。它将消除您遇到的异常,但一旦超过该限制,服务器将开始拒绝所有传入请求。因此,有效的t与此类似:服务器已关闭。

谢谢,这似乎是合理的。使用网络模块实现代理概念的最佳方式是什么,或者除了套接字销毁之外,还可以进行哪些性能改进?@brielov取决于协议。如果您想从头实现HTTP客户端,那么实现keep alive可以吗提高性能。对于使用TCP套接字的其他用例,您可以查看流行库正在做什么(例如数据库连接器)。我看到的是,它们打开多个TCP套接字,尝试重新使用相同的连接。只有出现错误时,它们才会破坏这些连接。(当然,如果您想要实现HTTP服务器或客户端,切换到HTTP模块或一些经过良好测试的库是最有意义的。)