Node.js使用readline读大文件同时写入数据库触发内存溢出问题求助
问题根因
核心是读写速度不匹配且没有做背压控制:
- 本地文件流式读取的速度极快,
line事件会高频触发 - 数据库写入属于网络IO,速度远低于本地文件读取
- 你的代码没有等待
LineEntity.create异步操作完成就继续读取下一行,导致大量未完成的数据库写入任务、关联的上下文数据持续堆积在内存中,垃圾回收机制无法释放这部分内存,最终触发溢出。
你做的两组对照测试能正常运行的原因也非常清晰:
- 单独运行循环写数据库:带
await的循环会等前一次写入完成再发起下一次请求,不会出现任务堆积;即使不带await,单场景下的任务堆积速度也远低于读写组合场景,短时间测试不会触及内存阈值 - 单独运行读文件打印逻辑:控制台打印的速度跟得上文件读取速度,没有异步任务堆积,内存自然稳定
解决方案
改造代码实现读取和写入的速度匹配,核心是在写入未完成时暂停文件读取,写入完成后再恢复读取:
const lineReader = readline.createInterface({ input: fs.createReadStream(filePath), crlfDelay: Infinity }); lineReader.on('line', async (line) => { // 暂停读取文件 lineReader.pause(); try { console.log(line); // 等待数据库写入完成 await LineEntity.create({line: "some data"}); } catch (err) { // 可自行补充错误处理逻辑,如日志记录、重试、丢弃本条数据等 console.error('数据写入失败:', err); } finally { // 写入完成后恢复读取 lineReader.resume(); } }); lineReader.on('close', () => { console.log('文件所有内容处理完成'); });
如果需要更高的处理效率,可以增加并发控制逻辑,比如允许同时最多10个写入任务并行,只要并发数未达阈值就继续读取,到达阈值再暂停,性能会比单条串行处理高很多,同时也不会出现内存溢出问题。
内容的提问来源于stack exchange,提问作者SexyMF
相关产品推荐
相关产品推荐

