Nodejs 一个关于stream write的问题

Nodejs 一个关于stream write的问题

代码如下: var net = require(‘net’); var conn = net.createConnection(6001, ‘127.0.0.1’); var str = “aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa”;

function cycle(){
  var result = conn.write(str);
  if(result == false){
      console.log(conn);
  }
}

for(var i = 1; i <= 500; i++){
   cycle();
}

上述伪码是一种业务场景。

看了一下node源代码,stream的writable.write会现将数据写入buffer,等待buffer超过限定值之后,在进行真正的写入。当buffer满了之后,这时候我代码中conn.write就会写入失败。node文档上说"Writes chunk to the stream. Returns true if the data has been flushed to the underlying resource. Returns false to indicate that the buffer is full, and the data will be sent out in the future",我的问题是,conn.write就会写入失败,数据在后面会发送,具体机制是怎么样的?然后这部分数据会存放在哪儿?

然后上面的场景使用多个连接不停的发送数据,会出现系统内存不停的增长,是和conn.write的机制有关系吗?

谢谢指教!!


6 回复

Node.js 中 Stream 的 write 方法详解

在 Node.js 中,Stream 是一种处理流式数据的重要方式。Stream 可以用于读取文件、网络请求等场景。当你使用 conn.write(str) 方法时,实际上是在尝试向流中写入数据。

数据写入机制

conn.write() 方法会尝试将数据写入内部缓冲区(buffer)。如果缓冲区未满,数据会被立即写入,并返回 true 表示数据已被成功写入。如果缓冲区已满,conn.write() 会返回 false,表示数据暂时未能写入,但会在未来某个时刻被发送出去。

缓冲区与内存管理

缓冲区的主要作用是平衡数据的写入速度与处理速度。当数据生成的速度快于处理速度时,缓冲区可以暂时存储这些数据,防止数据丢失。但是,如果数据量过大,可能会导致内存占用过高,从而影响系统性能。

示例代码

var net = require('net');
var conn = net.createConnection(6001, '127.0.0.1');
var str = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa";

function cycle() {
  var result = conn.write(str);
  if (result === false) {
    console.log("Buffer is full, waiting for space...");
  } else {
    console.log("Data written successfully.");
  }
}

// 模拟大量数据写入
for (var i = 1; i <= 500; i++) {
  cycle();
}

数据存放位置

conn.write() 返回 false 时,未写入的数据会暂时存储在内部缓冲区中。Node.js 会自动管理这些缓冲区,确保数据不会丢失。一旦缓冲区有足够的空间,Node.js 会自动将这些数据写入目标资源(如网络连接)。

内存增长问题

如果你发现内存占用不断增加,可能是因为缓冲区持续累积未处理的数据。这通常发生在以下情况:

  • 网络连接不稳定或速度较慢。
  • 处理数据的速度跟不上数据生成的速度。
  • 服务器端处理数据的速度较慢。

为了解决这个问题,你可以采取以下措施:

  1. 增加缓冲区大小:可以通过设置 highWaterMark 参数来调整缓冲区大小。
  2. 优化数据处理逻辑:确保数据处理速度与生成速度匹配。
  3. 错误处理:在数据无法写入时,采取适当的错误处理逻辑,例如重试或通知用户。

希望以上内容能帮助你更好地理解 conn.write() 的工作机制及内存管理。


编辑器不会用,上面的代码有点问题,分开的。我再贴一下试试:

var net = require('net');
var conn = net.createConnection(6001, '127.0.0.1');
var str = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa";

function cycle(){ var result = conn.write(str); if(result == false){ console.log(conn); } }

for(var i = 1; i <= 500; i++){ cycle(); }

顶一下我的问题!!!

发送数据太快了,内核都有发送缓冲区的,超过缓冲区大小的数据无法立即发送出去,这部分数据就是你要发的数据,所以你的node进程的内存会不断变大.

请问这个缓冲区是内核开辟的还是node开辟呢?而且上述代码这样的发送应该不会超过内核的承载能力吧!

在 Node.js 中,streamwrite 方法用于向流中写入数据。当你调用 conn.write(str) 时,如果底层资源(如网络连接)无法立即处理这些数据,那么数据会被暂存到内部的缓冲区中。一旦底层资源准备好处理这些数据,它们将被逐个取出并发送。

具体机制

  • 返回值conn.write(str) 返回一个布尔值。如果返回 true,表示数据已成功写入底层资源。如果返回 false,则表示数据已暂存到缓冲区中,需要稍后处理。

  • 缓冲区:当缓冲区满时,conn.write 会返回 false。这意味着你正在尝试写入的数据暂时无法被发送出去,直到缓冲区中的数据被处理完毕。

示例代码

const net = require('net');
const conn = net.createConnection(6001, '127.0.0.1');

const str = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa";

function cycle() {
    const result = conn.write(str);
    if (!result) {
        console.log('Buffer is full, data is being buffered.');
    } else {
        console.log('Data written successfully.');
    }
}

setInterval(() => {
    cycle();
}, 100); // 每100毫秒执行一次

数据存放位置

  • conn.write 返回 false 时,未发送的数据会被暂存到内部缓冲区中。这些数据最终会被发送到底层资源,例如网络连接。

系统内存增长问题

  • 如果你使用多个连接不停地发送大量数据,可能会导致系统内存不断增长,这是因为每个连接都有自己的缓冲区来暂存数据。
  • 你可以通过监听 drain 事件来确保缓冲区清空后再继续写入数据,从而避免内存溢出。

解决方案

conn.on('drain', () => {
    console.log('Buffer drained, ready for new writes.');
});

这样,你可以在缓冲区清空后继续写入新的数据。

回到顶部