Non-blocking I/O cho phép Node.js xử lý hàng nghìn connections trên 1 thread — tránh readFileSync/JSON.parse(largeData)/vòng lặp nặng vì chúng block event loop và làm tất cả requests khác phải chờ.
- Non-blocking I/O hoạt động nhờ libuv delegate I/O operations cho OS kernel hoặc thread pool: khi gọi
fs.readFile(), Node.js đăng ký callback rồi trả control về event loop ngay lập tức, OS xử lý I/O ở background, khi xong thêm callback vào event queue để event loop xử lý. - So với blocking model Apache (thread-per-request): Apache cấp 1 thread/request, thread block khi chờ DB query — 1000 concurrent requests cần 1000 threads (~1GB RAM).
- Node.js single-threaded xử lý 1000 requests trên 1 thread vì hầu hết thời gian chờ I/O là idle.
- Throughput thực tế: Node.js thường đạt 10k-50k req/s cho I/O-heavy API, so với Apache ~1k-5k req/s.
- Khi nào blocking xảy ra accidentaly:
fs.readFileSync(),JSON.parse(largeData), vòng lặp tính toán nặng,crypto.pbkdf2Sync()— tất cả đều block event loop và làm tất cả requests khác phải chờ. - Solution: Worker Threads cho CPU-intensive, luôn dùng async variants.
Non-blocking I/O lets Node.js handle thousands of connections on one thread — avoid readFileSync/JSON.parse(largeData)/heavy loops as they block the event loop and force all other requests to wait.
- Non-blocking I/O works because libuv delegates I/O operations to the OS kernel or a thread pool: when
fs.readFile()is called, Node.js registers a callback and immediately returns control to the event loop; the OS handles I/O in the background, and when done adds the callback to the event queue for the event loop to process. - Compared to Apache's blocking model (thread-per-request): Apache allocates one thread per request, and threads block while waiting for a DB query — 1,000 concurrent requests require 1,000 threads (~1GB RAM).
- Node.js single-threaded handles 1,000 requests on one thread because most of the time waiting on I/O is idle.
- Real-world throughput: Node.js typically reaches 10k-50k req/s for I/O-heavy APIs, vs Apache's ~1k-5k req/s.
- When blocking happens accidentally:
fs.readFileSync(),JSON.parse(largeData), heavy computation loops,crypto.pbkdf2Sync()— all block the event loop and force all other requests to wait. - Solution: use Worker Threads for CPU-intensive work and always use async variants.