Caché: no recalcular lo que ya sabes
Si una operación es cara (una consulta pesada, una llamada externa) y su resultado cambia poco, cachéalo. Un almacén en memoria como Redis guarda pares clave-valor con acceso casi instantáneo y un TTL (tiempo de vida) opcional:
// Pseudocódigo conceptual:
let datos = await redis.get("usuario:1");
if (!datos) { // "miss": no estaba en caché
datos = await db.buscarUsuario(1);
await redis.set("usuario:1", datos, "EX", 60); // expira en 60 s
}
El patrón cache-aside: mira la caché primero; si hay hit, devuélvelo; si hay miss, calcula, guarda en caché y devuelve.
Usar todos los núcleos
Un proceso de Node usa un núcleo para tu JS. Para aprovechar una máquina con varios núcleos hay dos herramientas complementarias:
- Clustering (
node:cluster): lanza varios procesos idénticos (workers) que comparten el mismo puerto. El sistema reparte las conexiones entrantes entre ellos. Resuelve el escalado de un servidor HTTP: más procesos atienden más peticiones en paralelo, y si uno cae, los demás siguen. worker_threads: hilos dentro de un proceso, con su propio event loop. Sirven para trabajo de CPU intensivo (procesar imágenes, cálculos pesados) sin bloquear el hilo principal.
No bloquear el event loop
Como tu JS es monohilo, una operación síncrona y larga congela TODO: mientras calcula, no se atiende ninguna otra petición.
// MAL: bloquea el event loop durante todo el bucle.
function sumaLenta(n) {
let total = 0;
for (let i = 0; i < n; i++) total += i; // si n es enorme, nadie más avanza
return total;
}
La regla de oro: mantén el hilo principal libre. El trabajo pesado de CPU va a
un worker_thread; el I/O (red, disco, BD) ya es asíncrono y no bloquea. Así el
event loop sigue aceptando y respondiendo peticiones.
Ejemplos
Cache-aside: hit evita recalcular
const cache = new Map();
function obtenerCaro(clave, calcular) {
if (cache.has(clave)) return cache.get(clave); // hit
const valor = calcular(); // miss: calcula
cache.set(clave, valor); // y guarda
return valor;
}
let veces = 0;
const calc = () => { veces++; return 42; };
obtenerCaro("x", calc);
obtenerCaro("x", calc); // segunda vez: hit, no recalcula
console.log(veces); // 1