Conceptos Básicos de Rendimiento
8 ejemplos para empezar con el Rendimiento para backends de Node.js - 6 básicos y 2 intermedios.
Busca en todas las páginas de la documentación
8 ejemplos para empezar con el Rendimiento para backends de Node.js - 6 básicos y 2 intermedios.
npm install -g clinic para perfilar (ver Suite clinic.js).hrtimeLos temporizadores de alta resolución superan a Date.now() para la medición de latencia.
import { createServer } from "node:http";
const server = createServer((req, res) => {
const start = process.hrtime.bigint();
res.end("ok");
const elapsedMs = Number(process.hrtime.bigint() - start) / 1_000_000;
console.log(JSON.stringify({ path: req.url, durationMs: elapsedMs }));
});
server.listen(3000);process.hrtime.bigint() es monotónico, no afectado por la deriva del reloj.Relacionado: Pruebas de Carga - saturación y p95 bajo concurrencia
Los percentiles importan más que los promedios para los SLO de API.
const durations: number[] = [];
function recordDuration(ms: number): void {
durations.push(ms);
if (durations.length > 10_000) durations.shift();
}
function p95(): number {
const sorted = [...durations].sort((a, b) => a - b);
const idx = Math.ceil(sorted.length * 0.95) - 1;
return sorted[idx] ?? 0;
}
// Exponer a través de /metrics o registrar cada N solicitudesRelacionado: Métricas Importantes - RPS, p95, tasa de errores
El retraso del bucle afecta a cada cliente concurrente, no solo a una ruta lenta.
import { monitorEventLoopDelay } from "node:perf_hooks";
const histogram = monitorEventLoopDelay({ resolution: 20 });
histogram.enable();
setInterval(() => {
console.log(JSON.stringify({
event: "loop_delay",
p99Ms: histogram.percentile(99) / 1e6,
maxMs: histogram.max / 1e6,
}));
histogram.reset();
}, 10_000);monitorEventLoopDelay mide cuánto se retrasa el bucle al ejecutar el trabajo programado.Relacionado: Detección de Bloqueo del Bucle de Eventos - herramientas de atribución
performance.mark para Rutas CríticasLas marcas integradas se integran con Chrome DevTools y clinic.js.
import { performance } from "node:perf_hooks";
async function fetchUser(id: string) {
performance.mark("fetchUser:start");
const user = await db.query("SELECT * FROM users WHERE id = $1", [id]);
performance.mark("fetchUser:end");
performance.measure("fetchUser", "fetchUser:start", "fetchUser:end");
return user;
}performance.getEntriesByName("fetchUser") devuelve arrays de duración para el análisis.Relacionado: Suite clinic.js - gráficos de llama para rutas críticas
Conoce las solicitudes por segundo en la concurrencia objetivo antes de cambiar el código.
# Prueba rápida (no una prueba de carga completa)
npx autocannon -c 50 -d 10 http://localhost:3000/health-c 50 simula 50 conexiones concurrentes, más cerca de la producción que un solo curl.Relacionado: Pruebas de Carga - escenarios de k6 y puntos de saturación
Los cuerpos JSON grandes bloquean el análisis de forma síncrona en el hilo principal.
import express from "express";
const app = express();
app.use(express.json({ limit: "1mb" }));
app.post("/events", (req, res) => {
// el cuerpo ya está limitado - rechaza los de tamaño excesivo en el analizador
res.status(201).json({ ok: true });
});limit devuelve 413 antes de que se ejecute tu manejador, lo que ahorra CPU en caso de abuso.Relacionado: Costo de Serialización JSON - dieta de la forma de la respuesta
La concurrencia sostenida revela bloqueos que las solicitudes individuales ocultan.
// script k6 - guardar como load-test.js
import http from "k6/http";
import { check, sleep } from "k6";
export const options = {
stages: [
{ duration: "1m", target: 50 },
{ duration: "3m", target: 50 },
{ duration: "1m", target: 0 },
],
thresholds: { http_req_duration: ["p(95)<200"] },
};
export default function () {
const res = http.get("http://localhost:3000/users");
check(res, { "status is 200": (r) => r.status === 200 });
sleep(0.1);
}thresholds falla la ejecución cuando p95 excede los 200ms, lo que impide las fusiones en caso de regresión.Relacionado: Rendimiento en Express - ajuste de Express bajo carga
Las fugas sospechosas necesitan evidencia antes de ajustar --max-old-space-size.
import { writeHeapSnapshot } from "node:v8";
import { writeFileSync } from "node:fs";
function captureHeap(label: string): void {
const path = writeHeapSnapshot();
writeFileSync(`/tmp/heap-${label}.json`, ""); // archivo marcador
console.log(JSON.stringify({ event: "heap_snapshot", label, path }));
}
// Llamar en SIGUSR2 o después de N solicitudes en staging
process.on("SIGUSR2", () => captureHeap("manual"));Relacionado: Ajuste de Memoria y GC -
--max-old-space-sizey banderas de GC
Versiones de la pila: Esta página fue escrita para Node.js 24.18.0 (LTS Activo), npm 10+, TypeScript 5.6+, Express 5, Fastify 5 y NestJS 11.
Revisado por Chris St. John·Última actualización: 16 jul 2026