FileDummy Logo
FileDummy
Lưu Trữ Đám Mây & CDN

Truyền Luồng (Stream) Tải Tệp Lớn Trong Node.js Tránh Lỗi Tràn Bộ Nhớ RAM

Cách sử dụng luồng đọc Node.js Stream và cơ chế backpressure để phân phối tệp tin dung lượng 1GB mà không tốn tài nguyên máy chủ.

20 tháng 9, 202610 phút đọc1,420 lượt xem
nodejsstreamingexpressfile-downloadperformance

Serving large files directly from Node.js without a CDN or object storage proxy requires streaming. Loading a 1GB file into memory with fs.readFileSync consumes 1GB of server RAM per connected user—rapidly leading to process termination.

Streaming Files with Node.js HTTP Streams

Node.js readable streams buffer only small chunks (typically 64KB) in memory at any given moment:

TypeScript
import http from 'http';
import fs from 'fs';
import path from 'path';

const server = http.createServer((req, res) => {
  const filePath = path.join(process.cwd(), 'files', 'large-dataset.pdf');

  fs.stat(filePath, (err, stats) => {
    if (err) {
      res.writeHead(404, { 'Content-Type': 'text/plain' });
      return res.end('File not found');
    }

    // Set binary response headers
    res.writeHead(200, {
      'Content-Type': 'application/pdf',
      'Content-Length': stats.size,
      'Content-Disposition': 'attachment; filename="large-dataset.pdf"',
      'Accept-Ranges': 'bytes',
    });

    const readStream = fs.createReadStream(filePath);

    // Automatically handles TCP backpressure
    readStream.pipe(res);

    // Handle client disconnects
    req.on('close', () => {
      readStream.destroy();
    });
  });
});

server.listen(3000, () => console.log('Download server running on port 3000'));
Verified Test Asset.pdf

Download our 500MB PDF sample file to test stream backpressure handling in your server code.

Tải File Mẫu 500MB PDF →

Understanding Stream Backpressure

When a server can read from disk faster than a client can receive data over the network, stream.pipe(res) automatically pauses the read stream until the client's socket drain buffer clears, preserving server memory.

NDL

Nguyễn Đại Long

Tác Giả

Backend Lead • Chuyên gia Kiến trúc Hệ thống Phân tán & Lưu trữ Đám mây

Hơn 4 năm kinh nghiệm thiết kế các hệ thống xử lý tệp tải lên thông lượng lớn, tối ưu hóa cơ sở dữ liệu và hạ tầng phân tán Cloudflare R2 / AWS S3. Người sáng lập FileDummy và Mạng lưới Hệ sinh thái NDL.

Bài viết này có hữu ích không?

Bấm Thích để ủng hộ tác giả và giúp bài viết lan tỏa tới cộng đồng lập trình viên.

Thảo Luận Kỹ Thuật & Đóng Góp Ý Kiến (0)

Chia sẻ kết quả benchmark, phản hồi các trường hợp biên hoặc đặt câu hỏi chuyên môn.

0/3000

Chưa có bình luận nào. Hãy là lập trình viên đầu tiên bắt đầu cuộc thảo luận!

Câu Hỏi Thường Gặp (FAQ)

Why does Node.js run out of memory when serving large files?

Using fs.readFileSync() or res.send(buffer) loads the entire file into heap memory. For a 1GB file with 10 concurrent downloads, that is 10GB of RAM. Use fs.createReadStream().pipe(res) instead — it reads in 64KB chunks, keeping memory constant regardless of file size.

What is backpressure in Node.js streams?

Backpressure occurs when the writable stream (HTTP response) cannot consume data as fast as the readable stream (file read) produces it. Using .pipe() handles backpressure automatically by pausing the file read when the response write buffer is full.

How do I add HTTP Range request support to my Node.js file server?

Parse the Range header, calculate the byte range, use fs.createReadStream(path, { start, end }), and respond with 206 Partial Content and the Content-Range header. This enables browser resume support and video seeking.

Bài Viết Liên Quan