ویژگی تصویر

مانیتورینگ و دیباگ در Node.js — مقدمه‌ای عملی و کاربردی

  /  Node.js   /  مانیتورینگ و دیباگ در Node.js
بنر تبلیغاتی الف
NodeJS - Node.js

مانیتورینگ و دیباگ در Node.js بخش حیاتی توسعه و نگهداری اپلیکیشن‌های تولیدی است. بدون ابزارها و روش‌های صحیح، تشخیص مشکلاتی مثل نشت حافظه، قفل شدن لوپ رویداد (event loop), یا خطاهای پراکنده بسیار دشوار می‌شود. در این مقاله مفاهیم، ابزارها و نمونه‌های عملی برای دیباگ و مانیتورینگ در محیط Node.js را به زبان ساده و حرفه‌ای بررسی می‌کنیم.

اصول و معیارهای مهم برای مانیتورینگ

  • متریک‌های پایه: استفاده از حافظه (RSS, heapUsed), مصرف CPU، طول صف رویداد (event loop lag) و تعداد اتصال‌ها.
  • لاگ‌گذاری ساختاریافته: ثبت لاگ‌ها با سطح (error, warn, info) و شناسه‌های همبسته (correlation id).
  • آلارم و آستانه‌ها: تعریف آستانه برای متریک‌های کلیدی و ارسال هشدار به کانال‌های مناسب.
  • پروفایلینگ دوره‌ای: نمونه‌برداری (sampling) یا رویه‌ای (instrumentation) برای یافتن تنگناها.

ابزارهای رایج و مقایسه سریع

ابزارکاربردبار‌گذاری
PM2مدیریت فرایند، مانیتورینگ ساده، لاگ‌هاکم
Prometheus + Grafanaجمع‌آوری متریک و داشبوردهای قابل تنظیممتوسط
Clinic (Flame / Doctor / Bubbleprof)پروفایلینگ CPU، I/O و event loopمتوسط تا زیاد (برای زمان تست)
Sentry / New Relic / Elastic APMردیابی خطا، performance tracing و APMمتوسط

دیباگ محلی و ابزارهای داخلی Node.js

Node.js امکاناتی مثل inspector، CLI debugger و flags مفید ارائه می‌دهد. برای توقف در اولین خط و اتصال به Chrome DevTools:

node --inspect-brk ./server.js

این دستور فرآیند Node را در حالت inspector اجرا می‌کند و با مرورگر (chrome://inspect) یا VSCode قابل اتصال است. کاربرد اصلی برای دیباگ محلی و بررسی call stack، breakpoints و scope‌هاست.

نمونه‌: مانیتور حافظه ساده

setInterval(() => {
  const mem = process.memoryUsage();
  console.log(`RSS: ${Math.round(mem.rss / 1024 / 1024)}MB, heapUsed: ${Math.round(mem.heapUsed/1024/1024)}MB`);
}, 10000);

این کد هر 10 ثانیه مصرف حافظه را چاپ می‌کند. برای محیط تولید بهتر است لاگ‌ها به سیستم لاگ مرکزی یا متریک اکسپورت شوند و از چاپ مستقیم در کنسول پرهیز شود.

پایش event loop و latency

برای تشخیص بلوکه شدن لوپ رویداد از ماژول native perf_hooks می‌توان استفاده کرد:

const { monitorEventLoopDelay } = require('perf_hooks');
const h = monitorEventLoopDelay({ resolution: 10 });
h.enable();
setInterval(() => {
  console.log('event loop delay (ms):', h.mean / 1e6);
  h.reset();
}, 5000);

این نمونه میانگین تاخیر لوپ رویداد را گزارش می‌کند که کمک می‌کند متوجه شویم عملیات‌های سنگین CPU یا بلاک‌کننده باعث مشکل شده‌اند.

متریک‌ها برای Prometheus (Express مثال)

const express = require('express');
const client = require('prom-client');
const app = express();

const collectDefault = client.collectDefaultMetrics;
collectDefault();

const httpReqs = new client.Counter({ name: 'http_requests_total', help: 'Total HTTP requests' });

app.use((req, res, next) => {
  httpReqs.inc();
  next();
});

app.get('/metrics', async (req, res) => {
  res.set('Content-Type', client.register.contentType);
  res.end(await client.register.metrics());
});

app.listen(3000);

این کد یک endpoint /metrics در اپلیکیشن اکسپرس ایجاد می‌کند که Prometheus می‌تواند آن را scrape کند. علاوه بر متریک‌های پیش‌فرض، می‌توان custom metric اضافه کرد تا داشبوردهای Grafana بسازید.

پروفایلینگ و تشخیص نشت حافظه

برای نشت حافظه از heap snapshot و ابزارهایی مثل Chrome DevTools یا heapdump استفاده کنید. در تولید اغلب از sampling profiler استفاده می‌شود تا overhead کم باشد. ابزارهایی مثل Clinic.js (npx clinic) برای گرفتن flamegraph و تحلیل performance بسیار مفیدند:

npx clinic flame -- node server.js

این فرمان اپلیکیشن را اجرا و در پایان یک flamegraph تولید می‌کند که نشان می‌دهد کجا بیشترین زمان CPU صرف شده است.

لاگ‌گذاری ساختاریافته و مدیریت خطا

  • از کتابخانه‌هایی مثل Pino یا Winston برای لاگ ساختاریافته (JSON) استفاده کنید.
  • Unhandled errors: حتما handler برای unhandledRejection و uncaughtException داشته باشید و فرایند را در صورت لازم ری‌استارت کنید (به کمک PM2 یا سیستم اورکستراسیون).

مثال ساده ثبت خطا:

process.on('unhandledRejection', (reason) => {
  console.error('Unhandled Rejection:', reason);
  // ارسال به Sentry یا لاگ مرکزی
});

ثبت این رویدادها کمک می‌کند خطاهایی که در promiseها نادیده گرفته می‌شوند را شناسایی کنید. در تولید بهتر است این موارد به یک سرویس خطاپذیر مثل Sentry ارسال شوند.

Tracing توزیع‌شده و correlation id

در میکروسرویس‌ها ضروری است درخواست‌ها قابل ردیابی بین سرویس‌ها باشند. از OpenTelemetry یا APM های تجاری استفاده کنید تا spans و traces بین سرویس‌ها جمع‌آوری شود. همچنین استفاده از correlation id در هدرها و لاگ‌ها امکان پیگیری بهتر را فراهم می‌آورد.

بهترین شیوه‌ها و نکات عملی

  • مانیتورینگ را از مرحله staging آغاز کنید و thresholdهای تولیدی را به تدریج تنظیم کنید.
  • در متریک‌ها Sampling و aggregation داشته باشید تا هزینه ذخیره‌سازی کم بماند.
  • در محیط تولید از ابزارهای با overhead کم (مثل sampling profiler یا event-loop delay) استفاده کنید.
  • پروفایلینگ کامل را در محیط تولید با احتیاط یا در محیط staging انجام دهید تا روی کاربران تأثیر نگذارد.
  • آلارم‌ها را هوشمندانه تنظیم کنید تا هشدارهای کاذب کم شود و تیم به هشدارهای واقعی توجه کند.

خلاصه و مسیر عمل

مانیتورینگ و دیباگ در Node.js ترکیبی از جمع‌آوری لاگ‌ها، متریک‌ها، tracing و پروفایلینگ است. ابزارهایی مثل Prometheus/Grafana، PM2، Clinic و APMها هر کدام نقش مکمل دارند. پیاده‌سازی لاگ ساختاریافته، تعریف آستانه و داشبوردهای کاربردی، و توانایی گرفتن پروفایل در زمان وقوع مشکل، مهم‌ترین گام‌ها برای بهبود قابلیت اطمینان و عملکرد اپلیکیشن هستند.

اگر نیاز به نمونه‌های بیشتر (مثل گرفتن heap snapshot برنامه‌ریزی‌شده یا نمونه‌های OpenTelemetry) دارید، می‌توانم کدهای دقیق‌تر و راهنمای گام‌به‌گام فراهم کنم.

آیا این مطلب برای شما مفید بود ؟

خیر
بله
موضوعات شما در انجمن: