Khi server Node.js “kêu cứu”
Anh em làm Node.js chắc không lạ gì cảnh server bỗng dưng lăn đùng ra chết hoặc phản hồi chậm như rùa dù CPU vẫn thấp. Mình từng quản lý một hệ thống xử lý data real-time với codebase khoảng 50K dòng. Cứ sau 4 tiếng chạy production, RAM lại vọt từ 500MB lên tận 4GB rồi dính lỗi OOM (Out of Memory). Lúc đó, việc mò mẫm từng dòng code hay đặt console.log khắp nơi đúng là ác mộng.
Cái “gót chân Achilles” của Node.js chính là cơ chế đơn luồng (single-threaded) của Event Loop. Chỉ cần một hàm đồng bộ chạy quá lâu hoặc một mảng dữ liệu không được giải phóng, toàn bộ ứng dụng sẽ bị nghẽn. Các công cụ mặc định như --inspect hay Chrome DevTools khá tốt. Tuy nhiên, đồ thị của chúng cực kỳ rối mắt với những ai mới tiếp cận. Đó là lý do mình chọn Clinic.js.
Bộ công cụ này gồm 4 module chuyên biệt: Doctor, Bubbleprof, Flame và Heapprofiler. Chúng giúp trực quan hóa hiệu năng thành các biểu đồ sinh động. Qua 6 tháng áp dụng, mình thấy Clinic.js giúp tiết kiệm tới 70% thời gian tìm nguyên nhân gốc rễ của các lỗi hiệu năng khó nhằn.
Cài đặt nhanh
Để bắt đầu, anh em chỉ cần môi trường Node.js sẵn có. Mình khuyên nên cài global để có thể triệu hồi “bác sĩ” này ở bất cứ project nào.
npm install -g clinic
Để mô phỏng tải (load test) nhằm bộc lộ lỗi, autocannon là cặp bài trùng không thể thiếu. Nó giúp chúng ta tạo ra hàng ngàn request giả lập để xem server chịu đựng đến đâu.
npm install -g autocannon
Quy trình “khám bệnh” thực tế
Clinic.js chia làm nhiều công cụ tùy theo triệu chứng của ứng dụng. Dưới đây là cách mình vận dụng chúng vào quy trình debug hàng ngày.
1. Clinic Doctor: Khám tổng quát
Mỗi khi thấy ứng dụng chậm mà không rõ lý do, mình luôn bắt đầu với clinic doctor. Nó sẽ theo dõi sát sao CPU, Event Loop Lag, Memory và số lượng Active Handles.
clinic doctor -- node server.js
Sau đó, mở một terminal khác và dùng autocannon để đẩy traffic vào:
autocannon -c 100 -d 20 http://localhost:3000
Khi dừng server (Ctrl+C), Clinic.js sẽ tự động bật tab trình duyệt hiển thị kết quả. Nếu thấy biểu đồ Event Loop xuất hiện các cột đỏ cao vút (thường trên 100ms), chắc chắn bạn đang có những hàm tính toán quá nặng làm chặn luồng chính.
2. Clinic Flame: Soi “điểm nóng” CPU
Nếu Doctor báo hiệu CPU bị nghẽn, đã đến lúc dùng clinic flame để vẽ Flamegraph. Biểu đồ này giúp chỉ mặt đặt tên hàm nào đang “ngốn” nhiều thời gian xử lý nhất.
clinic flame -- node server.js
Kinh nghiệm là hãy tập trung vào độ rộng của các thanh. Thanh càng rộng nghĩa là hàm đó chiếm CPU càng lâu. Có lần mình phát hiện một hàm Regex cực kỳ phức tạp bị gọi liên tục trong vòng lặp chỉ nhờ nhìn vào biểu đồ này.
3. Clinic Bubbleprof: Kiểm tra độ trễ bất đồng bộ
Node.js mạnh ở I/O bất đồng bộ, và Bubbleprof là công cụ tốt nhất để soi độ trễ khi gọi Database hoặc API bên thứ ba.
clinic bubbleprof -- node server.js
Nó vẽ ra các “bong bóng” (bubbles). Bong bóng càng to chứng tỏ thời gian chờ đợi (latency) ở đó càng lâu. Nếu thấy một bong bóng khổng lồ nằm ở phần truy vấn Database, hãy kiểm tra ngay Index hoặc tối ưu lại Query.
Xử lý dứt điểm Memory Leak
Để khắc phục lỗi tràn RAM (Memory Leak) nhắc ở đầu bài, mình dùng clinic heapprofiler. Công cụ này soi rõ object nào đang “lỳ lợm” nằm lại trong bộ nhớ mà không bị Garbage Collector dọn dẹp.
Case study thực tế: Mình phát hiện một mảng const cache = [] khai báo global. Mỗi request lại push thêm một object vào mà không bao giờ xóa. Heapprofiler cho thấy mảng này chiếm tới 80% dung lượng Heap. Sau khi chuyển sang dùng LRU Cache với giới hạn 1000 phần tử, RAM đã ổn định ở mức 200MB.
Lưu ý sống còn khi dùng trên Production
Dù rất mạnh, nhưng mình khuyên anh em không nên chạy Clinic.js trực tiếp trên server production đang có khách dùng. Profiling có thể gây ra mức overhead (tốn thêm tài nguyên) từ 15-30%. Cách tốt nhất là:
- Dựng môi trường Staging có cấu hình tương đương Production.
- Sử dụng dữ liệu thật đã được ẩn danh (sanitize) để tái hiện lỗi.
- Dùng
autocannongiả lập lượng traffic tương đương lúc xảy ra sự cố.
Đừng bao giờ đoán lỗi bằng cảm giác. Trước khi sửa bất cứ dòng code nào, hãy nhìn vào số liệu thực tế. Việc có các biểu đồ trực quan từ Clinic.js không chỉ giúp bạn tìm lỗi nhanh hơn mà còn là bằng chứng thép khi giải trình với team hoặc cấp trên về các vấn đề hệ thống.

