Latenza di memoria su un server cloud: misurata, non stimata

Latenza di memoria su un server cloud: misurata, non stimata

Latenza di memoria su un server cloud: misurata, non stimata

In breve (verificato il 2026-11-01): Un post arrivato in prima pagina su Hacker News questo fine settimana sostiene che una CPU al 100% spesso sta solo aspettando la RAM, e mostra un GROUP BY diventato più veloce facendo più lavoro ma toccando meno la memoria. Abbiamo provato la stessa idea sul server cloud che scrive questo blog: una lettura costa circa 2 ns quando i dati stanno in L1 e circa 200 ns con un working set di 256 MB, circa cento volte di più. Per chi noleggia server questo divario conta più del numero di core nell'ordine. Qui sotto lo script, i nostri numeri e cosa cambiano nella scelta tra cloud e dedicato.

Fonte. "It's the memory latency, stupid" di Maor Kern (Pivot / Epsio Labs, pubblicato il 2026-10-28), discusso su Hacker News con 175 punti al 2026-11-01. I loro numeri sono riportati come li pubblica il post; i nostri li abbiamo misurati noi.

Cosa ha misurato il post di Pivot

Il test è una query, GROUP BY UserID sulla tabella "hits" di ClickBench (circa 99 milioni di righe, circa 17 milioni di utenti distinti), fissata su un core di un server bare metal AMD EPYC 9124 con 128 GB DDR5. Una tabella hash semplice con 17 milioni di chiavi non sta in nessuna cache, quindi quasi ogni ricerca va in RAM. Dividere prima le righe in 4096 partizioni, ognuna con una piccola tabella hash, aggiunge lavoro ma tiene ogni tabella in cache:

Metrica (un core) Tabella hash semplice Partizionamento radix
Tempo, 1a / 2a esecuzione 3.9 s / 3.6 s 3.3 s / 2.7 s
Slot in attesa della memoria 50.1% 23.5%
Slot con lavoro utile 16.1% 32.2%
Letture dalla DRAM 76.2 milioni 25.7 milioni

La versione partizionata esegue più operazioni (19.4 miliardi contro 11.4 miliardi) e finisce comunque per prima. La versione ottimizzata dell'autore ha impiegato 1.85 s su un core e 0.17 s su tutti i 16. La lezione non riguarda un solo database: "CPU 100%" in top dice che il core non è inattivo, non che sta calcolando.

Misuralo tu: memlat.js

Il modo classico per vedere la latenza è un pointer chase: un array in cui ogni cella contiene l'indice della successiva, in ordine casuale, distanti una linea di cache (64 byte). Ogni lettura dipende dalla precedente, quindi la CPU non può né precaricare né sovrapporle, e il tempo per salto è la latenza del livello in cui vive il working set. Sulla nostra macchina del blog non c'è un compilatore C, quindi è JavaScript per Bun: il JIT trasforma il ciclo in poche istruzioni macchina, il che aggiunge un po' a ogni numero. Confronta i gradini, non i valori assoluti. Salvalo come 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

Output, eseguito su un server DCXV Cloud con Bun 1.4.4 il 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 seconda esecuzione la stessa mattina si è discostata al massimo di 2 ns fino a 1 MB e al massimo di 12 ns oltre:

Working set ns per lettura, esecuzione 1 / 2 Dove vive
32 KB 2.2 / 2.4 cache dati L1
256 KB 12.5 / 10.5 L2, in parte già L3
1 MB 24.3 / 24.3 L3
16 MB 138.4 / 137.2 page walk, L3 e DRAM
256 MB 205.1 / 193.5 DRAM

Cosa dicono i numeri

  1. Il guest non vede le cache reali. La VM dichiara 4 MB di L2 e 16 MB di L3; Intel indica 50 MB di cache per lo Xeon E5-2698 v4 (Intel ark, verificato il 2026-11-01). L'hypervisor presenta una sua topologia, e lscpu dentro un server cloud legge quella, non il silicio. Misura l'hardware invece di fidarti delle etichette.
  2. Il crollo arriva molto prima che la cache sia piena. Tra 1 MB e 4 MB la latenza si moltiplica per cinque, ben sotto i 50 MB. Con pagine da 4 KB un percorso casuale su 4 MB tocca 1.024 pagine, più di quante ne tenga il TLB, e in una VM un miss del TLB percorre le tabelle delle pagine del guest e dell'host; inoltre la L3 è condivisa con gli altri core del socket. Non abbiamo separato queste cause. La conclusione pratica è la stessa: in una VM pianifica come se il tuo working set veloce fosse di pochi megabyte.
  3. Più RAM non è RAM più veloce. Da 1 MB a 256 MB il costo per lettura cresce di circa otto volte. Più gigabyte danno capacità, non velocità; ciò che accelera un lavoro limitato dalla latenza è un insieme caldo più piccolo, come mostra il partizionamento di Pivot.

Cosa significa se noleggi server

  • I server cloud vanno bene per la maggior parte di app web, API e piccoli database: i loro dati caldi stanno in cache, e aspettano la rete o il disco molto prima della RAM. Dimensionali sull'uso di memoria misurato, come nella nostra guida al dimensionamento dei server cloud.
  • I server dedicati convengono quando un grande working set viene letto a caso tutto il giorno: analytics, grandi hash join, cache in memoria, un server PostgreSQL i cui indici non stanno più in RAM. Hai tutta la L3 e tutti i canali di memoria senza vicini, e puoi attivare le huge pages, che riducono i miss del TLB. Configurane uno nella pagina server dedicato.
  • Prima di qualsiasi upgrade, esegui il test sul server che hai già e verifica se il tuo lavoro lento è limitato dalla latenza. Raddoppiare i core non aiuta un thread fermo metà del tempo. La memoria stessa è rincarata quest'anno, vedi RAM server nel 2026, quindi la soluzione più economica spesso è codice che ne tocca meno.

Prova prima di comprare

I nostri data center Tier III a Praga e Covilhã offrono server cloud e server dedicati. Avvia un server cloud, esegui memlat.js accanto al tuo carico e invia l'output a sales@dcxv.com: ti aiuteremo a capire se un server dedicato cambierebbe i numeri.

10.000 commenti nei consigli USA: cosa cambia per i clienti
clouddedicatedinfrastructure

10.000 commenti nei consigli USA: cosa cambia per i clienti

Un dataset codifica 10.202 interventi sui data center negli USA: 90,5% contrari, l'acqua al primo posto. Lo ricontiamo e spieghiamo cosa cambierà per i clienti.

Latenza di memoria su un server cloud: misurata, non stimata
clouddedicatedinfrastructure

Latenza di memoria su un server cloud: misurata, non stimata

Un post virale dice che una CPU occupata spesso aspetta solo la RAM. Abbiamo misurato la latenza da L1 a DRAM sul nostro server cloud e spieghiamo perché conta.

Altman vuole la tua DRAM nei data center: RAM server 2026
cloudaipricinginfrastructure

Altman vuole la tua DRAM nei data center: RAM server 2026

Sam Altman dice che la memoria dei PC resta inutilizzata e va nei data center. Cosa significa la scarsità di DRAM del 2026 per i server e uno script di misura.

PHP2Shell: come verificare e correggere le falle RCE di PHP
clouddedicatedhosting

PHP2Shell: come verificare e correggere le falle RCE di PHP

PHP2Shell (CVE-2026-109618, CVE-2026-109619) fa sì che una richiesta non autenticata esegua codice in PHP. Versioni corrette, script testato, rimedi in php.ini e piano.

Brotli CVE-2026-111497: aggiornare Node.js, Bun e Python
cloudnetworkinginfrastructure

Brotli CVE-2026-111497: aggiornare Node.js, Bun e Python

Una falla del decoder Brotli (CVE-2026-111497) può eseguire codice via fetch() in Node.js e Bun o nei client HTTP Python. Versioni corrette, script di verifica e ricostruzione.