تحلیل عملکرد و Benchmark در Node.js
در توسعهٔ اپلیکیشنهای سمت سرور با Node.js، تحلیل عملکرد (Performance Analysis) و بنچمارکگیری (Benchmarking) نقش حیاتی دارند. بدون اندازهگیری دقیق نمیتوان تصمیمات بهینهسازی را بهطور منطقی گرفت. این مقاله چگونگی اندازهگیری، ابزارهای مفید، نکات عملی و مثالهای واقعی را برای تحلیل عملکرد در Node.js پوشش میدهد.
چرا Benchmark و پروفایلینگ مهم است؟
- تشخیص گلوگاهها: آیا مشکل CPU است یا I/O؟
- پیشبینی مقیاسپذیری: چگونه سیستم رفتار میکند با افزایش بار؟
- اعتبارسنجی بهینهسازی: آیا تغییر کُد واقعاً بهتر شده یا فقط در شرایط خاص؟
- مقایسهٔ راهکارها: چند الگوریتم یا طراحی را در شرایط یکسان بسنجیم.
مفاهیم کلیدی و معیارها
- Throughput: تعداد درخواستها در ثانیه.
- Latency: زمان پاسخدهی (میانگین، p95، p99).
- CPU Utilization: درصد استفاده از پردازنده.
- Event Loop Lag: تأخیر در حلقهٔ رویداد که نشاندهندهٔ بلاک شدن کد است.
- Memory / GC: نشتی حافظه و فراخوانیهای جمعآوری زباله.
ابزارهای کاربردی
- perf_hooks (داخل Node): برای اندازهگیری event loop delay و PerformanceObserver.
- –prof / –prof-process: تولید پروفایل V8 و تحلیل تایملاین اجرا.
- Clinic.js (doctor, flame, bubbleprof): تحلیل عمیق و visualization.
- autocannon / artillery / wrk: ابزارهای بارگذاری (load testing) برای HTTP.
- Chrome DevTools: پروفایلینگ CPU و heap snapshot از طریق inspector.
- Benchmark.js: برای microbenchmarkهای معتبر و آماری.
پنج اشتباه رایج در بنچمارکگیری
- اجرای بنچمارک روی محیط توسعه (بدون شبیهسازی بار و شبکه واقعی).
- نادیده گرفتن warm-up و JIT: اجرای یکبار قبل از گرفتن نتایج.
- استفاده از microbenchmarkهای ناامن که خروجی واقعی اپلیکیشن را نشان نمیدهند.
- فراموش کردن درصد خطاها (p95/p99) و تنها نگاه به میانگین.
- بدون تکرار و آمارگیری (sampling, standard deviation) گرفتن نتایج.
مثال عملی 1 — اندازهگیری Event Loop Delay با perf_hooks
const { monitorEventLoopDelay } = require('perf_hooks');
const h = monitorEventLoopDelay({ resolution: 10 });
h.enable();
setInterval(() => {
console.log({
min: h.min / 1e6,
max: h.max / 1e6,
mean: h.mean / 1e6,
stddev: h.stddev / 1e6
});
h.reset();
}, 1000);
// بار مصنوعی برای تست
setInterval(() => {
const start = Date.now();
while (Date.now() - start < 50) {} // بلاک کردن CPU به مدت 50ms
}, 500);این کد از ماژول داخلی perf_hooks استفاده میکند تا تأخیر حلقهٔ رویداد را با رزولوشن 10 میلیثانیه مانیتور کند. هر ثانیه آمار min، max، mean و stddev چاپ میشود. بخش دوم کد یک بار مصنوعی برای تولید event loop lag ایجاد میکند تا تأثیر بلاک شدن CPU مشاهده شود.
مثال عملی 2 — Microbenchmark قابل اعتماد با Benchmark.js
const Benchmark = require('benchmark');
const suite = new Benchmark.Suite();
function methodA() {
// نمونهٔ کاری سبک
return Array.from({length: 100}, (_, i) => i).reverse();
}
function methodB() {
const arr = [];
for (let i = 0; i console.log(String(event.target)))
.on('complete', function() {
console.log('Fastest is ' + this.filter('fastest').map('name'));
})
.run({ 'async': false });این مثال با Benchmark.js دو روش را در شرایط یکسان مقایسه میکند و نتایج آماری مثل ops/sec و خطای استاندارد را برمیگرداند. Benchmark.js خودش warm-up و تکرار را مدیریت میکند تا نتایج قابل اتکایی بدست آید.
مثال عملی 3 — انتقال کارهای CPU-bound به worker_threads
// main.js
const { Worker } = require('worker_threads');
function runTask(data) {
return new Promise((res, rej) => {
const w = new Worker('./worker.js', { workerData: data });
w.on('message', res);
w.on('error', rej);
w.on('exit', code => {
if (code !== 0) rej(new Error(`Worker stopped with ${code}`));
});
});
}
(async () => {
const result = await runTask(40);
console.log('fib(40)=', result);
})();
// worker.js
const { parentPort, workerData } = require('worker_threads');
function fib(n) {
if (n < 2) return n;
return fib(n - 1) + fib(n - 2);
}
const res = fib(workerData);
parentPort.postMessage(res);در این مثال، محاسبات سنگین بازگشتی فیبوناچی به یک Worker منتقل شدهاند تا حلقهٔ رویداد در thread اصلی بلاک نشود. این الگو برای کارهای CPU-bound مقیاسپذیری و پاسخدهی سیستم را بهطور چشمگیر افزایش میدهد.
چگونه نتایج را تفسیر کنیم
نمونهای از جدول معیارهای معمول در یک تست بار:
| متریک | معنی | هدف |
|---|---|---|
| Throughput (req/s) | درخواست در ثانیه | بالا |
| Avg Latency (ms) | میانگین زمان پاسخ | پایین |
| p95 / p99 (ms) | لیتنها در درصدهای بالا | پایین و پایدار |
| Event Loop Lag (ms) | تاخیر حلقه رویداد | < 50ms معمولاً مناسب |
نکات عملی و بهترین روشها
- همیشه warm-up انجام دهید و چند اجرای مستقل داشته باشید.
- متغیرهای محیط (CPU governor، توربو بوست، container limits) را ثابت نگهدارید.
- برای تستهای مقیاسپذیری از ابزار load testing واقعی مانند autocannon استفاده کنید.
- پروفایل CPU و heap را در بار واقعی بگیرید و به دنبال توابع “hot” باشید.
- GC tuning تنها در صورت نیاز و با درک عمیق از الگوهای حافظه انجام شود.
جمعبندی و استراتژی عملی
تحلیل عملکرد در Node.js ترکیبی از بنچمارکهای بار (throughput/latency)، پروفایلینگ دقیق (CPU/heap) و بررسی رفتار event loop است. ابزارهای داخلی مانند perf_hooks و امکانات V8 به همراه ابزارهای اکوسیستم (clinic، autocannon، Benchmark.js) مجموعهٔ قدرتمندی برای شناسایی و رفع گلوگاهها فراهم میکنند. همیشه نتایج را آماری، قابل تکرار و در محیطی ثابت بگیرید تا تصمیمات بهینهسازی واقعا موثر باشند.
آیا این مطلب برای شما مفید بود ؟




