Node.js 效能監控需要採用與傳統伺服器環境不同的方法。單線程事件循環、垃圾收集記憶體模型和非同步 I/O 創建了通用 CPU 和記憶體指標無法單獨捕獲的獨特故障模式。本文介紹了保持 Node.js 應用程式在生產環境中平穩運行所需的基本指標和工具。
為什麼 Node.js 效能監控有所不同
與多執行緒伺服器中緩慢的操作僅阻塞一個執行緒不同,Node.js 中的單一 CPU 密集型操作會阻塞整個事件循環,從而停止所有並發請求。垃圾收集暫停可能會導致不可預測的延遲高峰。常見的失敗模式包括事件循環飢餓、未清理的閉包導致的記憶體洩漏、回調抖動以及未處理的承諾拒絕默默吞下錯誤。了解這些特徵是有效監控的第一步。
事件循環滯後
事件循環延遲測量調度計時器回呼與其實際執行之間的延遲。這是 Node.js 進程最重要的健康指標。
const { monitorEventLoopDelay } = require("perf_hooks");
const histogram = monitorEventLoopDelay();
histogram.enable();
// In your health check endpoint:
setInterval(() => {
const lag = histogram.mean / 1e6; // Convert nanoseconds to milliseconds
histogram.reset();
if (lag > 50) logger.warn({ eventLoopLag: lag }, "Event loop lag detected");
}, 10000);
| 滯後 | 解讀 |
|---|---|
| < 10 毫秒 | 健康 |
| 10–50 毫秒 | 關於 — 調查 |
| > 50 毫秒 | 關鍵-需要立即採取行動 |
常見原因包括同步 CPU 密集型操作、大負載上的過多 JSON 解析以及主執行緒中執行的資料庫查詢最佳化不佳。
垃圾收集指標
V8 的垃圾收集器分兩個階段運行:快速的清理(年輕代)和較慢的標記-清除-壓縮(老年代)。長時間或頻繁的 GC 暫停會直接影響 p99 延遲。
const { PerformanceObserver } = require("perf_hooks");
const obs = new PerformanceObserver((list) => {
for (const entry of list.getEntries()) {
if (entry.detail.kind === "gc") {
logger.warn({
gcDuration: entry.duration,
gcKind: entry.detail.kind,
gcType: entry.detail.gctype,
}, "GC pause detected");
}
}
});
obs.observe({ entryTypes: ["gc"] });
高分配率會觸發頻繁的 GC 週期,從而增加 CPU 開銷和暫停時間。緩解策略包括熱路徑的物件池、減少請求處理程序中的臨時物件分配以及在安全性時對大緩衝區使用 Buffer.allocUnsafe 。
記憶體堆分析
Node.js 透過 process.memoryUsage() 公開記憶體使用情況,它傳回 rss、heapTotal、heapUsed、external 和 arrayBuffers。為了進行更深入的分析,堆快照準確地揭示了哪些物件正在保留記憶體。
const { writeHeapSnapshot } = require("v8");
const used = process.memoryUsage();
for (const [key, value] of Object.entries(used)) {
logger.info({ metric: `memory.${key}`, value: Math.round(value / 1024 / 1024) }, "Memory usage");
}
// Trigger snapshot on high memory
if (used.heapUsed / used.heapTotal > 0.8) {
writeHeapSnapshot(`/tmp/heap-${Date.now()}.heapsnapshot`);
}
分析 Chrome DevTools 中的快照以識別常見的洩漏模式:不斷增長的事件偵聽器計數、未逐出的陳舊快取、未釋放的 setInterval 計時器以及意外的全域變數累積。
CPU 分析
Node.js 包含一個透過 --prof 標誌啟動的內建分析器。產生火焰圖以視覺化 CPU 時間的消耗:
node --prof app.js
# After load testing:
node --prof-process isolate-*.log > processed.txt
Clinic.js 提供了一個更用戶友好的套件,其中包括用於 CPU 分析的 Flame 工具、用於非同步延遲的 Bubbleprof 以及用於整體健康建議的 Doctor。火焰圖頂部的寬塊表示熱函數;深堆疊意味著重構的機會。
// To enable the built-in profiler programmatically
const inspector = require("inspector");
const session = new inspector.Session();
session.connect();
session.post("Profiler.enable");
session.post("Profiler.start");
// ... after workload ...
session.post("Profiler.stop", (err, { profile }) => {
// Process or export profile data
});
開放遙測集成
OpenTelemetry 提供了一個與攤販無關的標準,用於收集追蹤、指標和日誌。 Node.js SDK 自動偵測 HTTP、gRPC、資料庫用戶端和訊息系統。
const { NodeSDK } = require("@opentelemetry/sdk-node");
const { getNodeAutoInstrumentations } = require("@opentelemetry/auto-instrumentations-node");
const { OTLPTraceExporter } = require("@opentelemetry/exporter-trace-otlp-http");
const sdk = new NodeSDK({
traceExporter: new OTLPTraceExporter({ url: "http://jaeger:4318/v1/traces" }),
instrumentations: [getNodeAutoInstrumentations()],
});
sdk.start();
對於自訂業務邏輯,建立手動跨距:
const { trace } = require("@opentelemetry/api");
const tracer = trace.getTracer("payment-service");
await tracer.startActiveSpan("processPayment", async (span) => {
span.setAttribute("orderId", order.id);
try { /* payment logic */ } finally { span.end(); }
});
APM 工具比較
| 工具 | 設定 | 優勢 | 開銷 |
|---|---|---|---|
| 資料狗APM | 代理制 | 深度 Node.js 整合、執行時間指標 | 低 |
| 新遺物 | npm 安裝 | 自動偵測、瀏覽器整合 | 中 |
| 彈性APM | 代理制 | 開源、ELK 原生 | 低 |
| OpenTelemetry + SigNoz | 手動設定 | 自架、完整 OTLP 支援 | 低 |
| PM2 + 關鍵指標 | 內建 | 輕量級、流程管理 | 最小 |
實用的監控設定
從最小限度開始:透過 prom-client 將流程指標(事件循環滯後、記憶體、垃圾收集)匯出到 Prometheus,然後在 Grafana 中視覺化。隨著複雜性的增加,添加 OpenTelemetry 進行分散式追蹤並整合 APM 工具以獲得更深入的見解。
const client = require("prom-client");
const gcHistogram = new client.Histogram({
name: "nodejs_gc_duration_seconds",
help: "Time spent in GC",
buckets: [0.001, 0.01, 0.1, 1],
});
開始迭代監控:首先是事件循環延遲和內存,然後是問題出現時的 CPU 分析和 GC 指標,最後是當您的應用程式擴展到分散式架構時使用 OpenTelemetry。

