Latencia de memoria en servidor cloud: medida, no supuesta

Latencia de memoria en servidor cloud: medida, no supuesta

Latencia de memoria en servidor cloud: medida, no supuesta

Respuesta corta (comprobado el 2026-11-01): Un post que llegó a la portada de Hacker News este fin de semana sostiene que una CPU al 100% a menudo solo está esperando a la RAM, y muestra un GROUP BY que se aceleró haciendo más trabajo pero tocando menos la memoria. Probamos la misma idea en el servidor cloud que escribe este blog: una lectura cuesta unos 2 ns cuando los datos caben en L1 y unos 200 ns con un conjunto de trabajo de 256 MB, unas cien veces más. Para quien alquila servidores, esa diferencia pesa más que el número de núcleos del pedido. Abajo están el script, nuestras cifras y lo que cambian al elegir entre cloud y dedicado.

Fuente. "It's the memory latency, stupid", de Maor Kern (Pivot / Epsio Labs, publicado el 2026-10-28), comentado en Hacker News con 175 puntos a 2026-11-01. Sus cifras se citan tal como las publica el post; las nuestras las medimos nosotros.

Qué midió el post de Pivot

La prueba es una consulta, GROUP BY UserID sobre la tabla "hits" de ClickBench (unos 99 millones de filas, unos 17 millones de usuarios distintos), fijada a un núcleo de un servidor bare metal AMD EPYC 9124 con 128 GB DDR5. Una tabla hash simple con 17 millones de claves no cabe en ninguna caché, así que casi cada búsqueda va a la RAM. Dividir antes las filas en 4096 particiones, cada una con una tabla hash pequeña, añade trabajo pero mantiene cada tabla en caché:

Métrica (un núcleo) Tabla hash simple Particionado radix
Tiempo, 1.ª / 2.ª ejecución 3.9 s / 3.6 s 3.3 s / 2.7 s
Slots esperando a memoria 50.1% 23.5%
Slots con trabajo útil 16.1% 32.2%
Lecturas desde DRAM 76.2 millones 25.7 millones

La versión particionada ejecuta más operaciones (19.4 mil millones frente a 11.4 mil millones) y aun así termina antes. La versión optimizada del autor tardó 1.85 s en un núcleo y 0.17 s en los 16. La lección no es de una sola base de datos: "CPU 100%" en top dice que el núcleo no está ocioso, no que esté calculando.

Mídelo tú mismo: memlat.js

La forma clásica de ver la latencia es un pointer chase: un array en el que cada posición guarda el índice de la siguiente, en orden aleatorio, separadas por una línea de caché (64 bytes). Cada lectura depende de la anterior, así que la CPU no puede precargar ni solaparlas, y el tiempo por salto es la latencia del nivel donde vive el conjunto de trabajo. En nuestra máquina del blog no hay compilador de C, así que es JavaScript para Bun: el JIT convierte el bucle en unas pocas instrucciones de máquina, lo que suma un poco a cada cifra. Compara los escalones, no los valores absolutos. Guárdalo como memlat.js:

// memlat.js - pointer-chase memory latency by working-set size (bun memlat.js)
import { readFileSync, readdirSync } from 'node:fs'

const cpu = readFileSync('/proc/cpuinfo', 'utf8').match(/model name\s*:\s*(.+)/)?.[1] ?? '?'
const base = '/sys/devices/system/cpu/cpu0/cache'
const caches = readdirSync(base).filter(d => d.startsWith('index')).map(d => {
  const r = f => readFileSync(`${base}/${d}/${f}`, 'utf8').trim()
  return `L${r('level')}${r('type') === 'Data' ? 'd' : r('type') === 'Instruction' ? 'i' : ''} ${r('size')}`
})
console.log(`CPU: ${cpu}\nCaches: ${caches.join(', ')}`)

// one random cycle through n slots, 64 bytes (16 x int32) apart: one cache line per hop
function ring(bytes) {
  const n = Math.max(2, Math.floor(bytes / 64))
  const order = new Uint32Array(n)
  for (let i = 0; i < n; i++) order[i] = i
  for (let i = n - 1; i > 0; i--) {
    const j = Math.floor(Math.random() * (i + 1))
    const t = order[i]; order[i] = order[j]; order[j] = t
  }
  const a = new Int32Array(n * 16)
  for (let i = 0; i < n; i++) a[order[i] * 16] = order[(i + 1) % n] * 16
  return a
}

function chase(a, hops) {
  let p = 0
  for (let i = 0; i < hops; i++) p = a[p]
  return p
}

const hops = 20_000_000
console.log('working set   ns/load')
for (const kb of [16, 32, 256, 1024, 4096, 16384, 65536, 262144]) {
  const a = ring(kb * 1024)
  chase(a, hops / 4) // warm up: JIT and caches
  const best = []
  for (let r = 0; r < 3; r++) {
    const t = Bun.nanoseconds()
    const sink = chase(a, hops)
    best.push((Bun.nanoseconds() - t) / hops)
    if (sink < 0) console.log(sink)
  }
  const label = kb >= 1024 ? `${kb / 1024} MB` : `${kb} KB`
  console.log(`${label.padStart(10)}   ${Math.min(...best).toFixed(1).padStart(7)}`)
}
bun memlat.js

Salida, ejecutado en un servidor DCXV Cloud con Bun 1.4.4 el 2026-11-01:

CPU: Intel(R) Xeon(R) CPU E5-2698 v4 @ 2.20GHz
Caches: L2 4096K, L1d 32K, L3 16384K, L1i 32K
working set   ns/load
     16 KB       2.0
     32 KB       2.2
    256 KB      12.5
      1 MB      24.3
      4 MB     122.2
     16 MB     138.4
     64 MB     164.7
    256 MB     205.1

Una segunda ejecución esa misma mañana se desvió como mucho 2 ns hasta 1 MB y como mucho 12 ns por encima:

Conjunto de trabajo ns por lectura, ejecución 1 / 2 Dónde vive
32 KB 2.2 / 2.4 caché de datos L1
256 KB 12.5 / 10.5 L2, desbordando a L3
1 MB 24.3 / 24.3 L3
16 MB 138.4 / 137.2 recorridos de tablas de páginas, L3 y DRAM
256 MB 205.1 / 193.5 DRAM

Lo que dicen las cifras

  1. El invitado no ve las cachés reales. La VM declara 4 MB de L2 y 16 MB de L3; Intel indica 50 MB de caché para el Xeon E5-2698 v4 (Intel ark, comprobado el 2026-11-01). El hipervisor presenta su propia topología, y lscpu dentro de un servidor cloud lee esa, no el silicio. Mide el hardware en lugar de fiarte de las etiquetas.
  2. El salto llega mucho antes de llenar la caché. Entre 1 MB y 4 MB la latencia se multiplica por cinco, muy por debajo de 50 MB. Con páginas de 4 KB, un recorrido aleatorio de 4 MB toca 1.024 páginas, más de las que caben en la TLB, y en una VM un fallo de TLB recorre las tablas de páginas del invitado y del host; además, la L3 se comparte con los demás núcleos del socket. No separamos estas causas. La conclusión práctica es la misma: en una VM, planifica como si tu conjunto de trabajo rápido fuera de unos pocos megabytes.
  3. Más RAM no es RAM más rápida. De 1 MB a 256 MB el coste por lectura crece unas ocho veces. Más gigabytes dan capacidad, no velocidad; lo que acelera una tarea limitada por latencia es un conjunto caliente más pequeño, como muestra el particionado de Pivot.

Qué significa si alquilas servidores

  • Los servidores cloud sirven para la mayoría de apps web, APIs y bases de datos pequeñas: sus datos calientes caben en caché y esperan a la red o al disco mucho antes que a la RAM. Dimensiónalos según el uso de memoria medido, como en nuestra guía de dimensionamiento de servidores cloud.
  • Los servidores dedicados compensan cuando un conjunto de trabajo grande se lee al azar todo el día: analítica, hash joins grandes, cachés en memoria, un servidor PostgreSQL cuyos índices ya no caben en RAM. Tienes toda la L3 y todos los canales de memoria sin vecinos, y puedes activar huge pages, que reducen los fallos de TLB. Configura uno en la página de servidor dedicado.
  • Antes de ampliar cualquiera de los dos, ejecuta la prueba en el servidor que ya tienes y comprueba si tu tarea lenta está limitada por latencia. Duplicar núcleos no ayuda a un hilo que pasa la mitad del tiempo parado. La memoria se encareció este año, ver RAM de servidor en 2026, así que la solución más barata suele ser código que la toque menos.

Prueba antes de comprar

Nuestros centros de datos Tier III en Praga y Covilha ofrecen servidores cloud y servidores dedicados. Arranca un servidor cloud, ejecuta memlat.js junto a tu propia carga y envía el resultado a sales@dcxv.com: te ayudaremos a decidir si un servidor dedicado cambiaría las cifras.

10.000 comentarios en concejos de EE. UU. y lo que implican
clouddedicatedinfrastructure

10.000 comentarios en concejos de EE. UU. y lo que implican

Un conjunto de datos codifica 10.202 intervenciones sobre centros de datos en EE. UU.: 90,5% en contra, el agua primero. Lo recontamos y vemos qué implica.

Latencia de memoria en servidor cloud: medida, no supuesta
clouddedicatedinfrastructure

Latencia de memoria en servidor cloud: medida, no supuesta

Un post viral dice que una CPU ocupada a menudo solo espera a la RAM. Medimos la latencia de L1 a DRAM en nuestro servidor cloud y explicamos qué implica.

Altman quiere tu DRAM en el data center: RAM de servidor 2026
cloudaipricinginfrastructure

Altman quiere tu DRAM en el data center: RAM de servidor 2026

Sam Altman dice que la memoria de los PC está ociosa y debe ir al centro de datos. Qué supone la escasez de DRAM de 2026 para servidores y un script para medir.

PHP2Shell: comprueba y parchea el RCE de PHP en tu servidor
clouddedicatedhosting

PHP2Shell: comprueba y parchea el RCE de PHP en tu servidor

PHP2Shell (CVE-2026-109618, CVE-2026-109619) permite que una petición sin autenticar ejecute código en PHP. Versiones corregidas, script probado, ajustes de php.ini y plan.

Brotli CVE-2026-111497: parchea apps Node.js, Bun y Python
cloudnetworkinginfrastructure

Brotli CVE-2026-111497: parchea apps Node.js, Bun y Python

Un fallo del decodificador Brotli (CVE-2026-111497) ejecuta código vía fetch() en Node.js y Bun o clientes HTTP de Python. Versiones corregidas, script probado y rebuild.