Latence mémoire d'un serveur cloud : mesurée, pas devinée

Latence mémoire d'un serveur cloud : mesurée, pas devinée

Latence mémoire d'un serveur cloud : mesurée, pas devinée

En bref (vérifié le 2026-11-01) : Un article arrivé en une de Hacker News ce week-end soutient qu'un CPU affiché à 100% attend souvent simplement la RAM, et montre un GROUP BY devenu plus rapide en faisant plus de travail mais en touchant moins la mémoire. Nous avons testé la même idée sur le serveur cloud qui écrit ce blog : une lecture coûte environ 2 ns quand les données tiennent dans le L1 et environ 200 ns avec un jeu de travail de 256 Mo, à peu près cent fois plus. Pour qui loue des serveurs, cet écart compte plus que le nombre de cœurs du bon de commande. Voici le script, nos chiffres et ce qu'ils changent dans le choix entre cloud et dédié.

Source. "It's the memory latency, stupid" de Maor Kern (Pivot / Epsio Labs, publié le 2026-10-28), discuté sur Hacker News avec 175 points au 2026-11-01. Leurs chiffres sont repris tels que l'article les publie ; les nôtres, nous les avons mesurés.

Ce que l'article de Pivot a mesuré

Le test est une requête, GROUP BY UserID sur la table "hits" de ClickBench (environ 99 millions de lignes, environ 17 millions d'utilisateurs distincts), épinglée sur un cœur d'un serveur bare metal AMD EPYC 9124 avec 128 Go de DDR5. Une table de hachage simple de 17 millions de clés ne tient dans aucun cache, donc presque chaque recherche va en RAM. Découper d'abord les lignes en 4096 partitions, chacune avec une petite table de hachage, ajoute du travail mais garde chaque table en cache :

Mesure (un cœur) Table de hachage simple Partitionnement radix
Durée, 1re / 2e exécution 3.9 s / 3.6 s 3.3 s / 2.7 s
Slots en attente de mémoire 50.1% 23.5%
Slots de travail utile 16.1% 32.2%
Lectures depuis la DRAM 76.2 millions 25.7 millions

La version partitionnée exécute plus d'opérations (19.4 milliards contre 11.4 milliards) et finit pourtant la première. La version optimisée de l'auteur a tourné en 1.85 s sur un cœur et 0.17 s sur les 16. La leçon ne concerne pas une seule base de données : "CPU 100%" dans top dit que le cœur n'est pas inactif, pas qu'il calcule.

Mesurez vous-même : memlat.js

La méthode classique pour voir la latence est le pointer chase : un tableau où chaque case contient l'indice de la suivante, dans un ordre aléatoire, espacées d'une ligne de cache (64 octets). Chaque lecture dépend de la précédente, le CPU ne peut donc ni précharger ni les superposer, et le temps par saut est la latence du niveau où vit le jeu de travail. Notre machine de blog n'a pas de compilateur C, c'est donc du JavaScript pour Bun : le JIT transforme la boucle en quelques instructions machine, ce qui ajoute un peu à chaque chiffre. Comparez les paliers, pas les valeurs absolues. Enregistrez-le sous 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

Résultat, exécuté sur un serveur DCXV Cloud avec Bun 1.4.4 le 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

Une seconde exécution le même matin a varié d'au plus 2 ns jusqu'à 1 Mo et d'au plus 12 ns au-delà :

Jeu de travail ns par lecture, exécution 1 / 2 Où il vit
32 Ko 2.2 / 2.4 cache de données L1
256 Ko 12.5 / 10.5 L2, débordant sur le L3
1 Mo 24.3 / 24.3 L3
16 Mo 138.4 / 137.2 parcours des tables de pages, L3 et DRAM
256 Mo 205.1 / 193.5 DRAM

Ce que disent les chiffres

  1. L'invité ne voit pas les vrais caches. La VM annonce 4 Mo de L2 et 16 Mo de L3 ; Intel indique 50 Mo de cache pour le Xeon E5-2698 v4 (Intel ark, vérifié le 2026-11-01). L'hyperviseur présente sa propre topologie, et lscpu dans un serveur cloud lit celle-ci, pas le silicium. Mesurez le matériel au lieu de croire les étiquettes.
  2. La falaise arrive bien avant que le cache soit plein. Entre 1 Mo et 4 Mo, la latence est multipliée par cinq, loin des 50 Mo. Avec des pages de 4 Ko, un parcours aléatoire de 4 Mo touche 1 024 pages, plus que le TLB n'en contient, et dans une VM un défaut de TLB parcourt les tables de pages de l'invité et de l'hôte ; le L3 est en outre partagé avec les autres cœurs du socket. Nous n'avons pas séparé ces causes. La conclusion pratique reste la même : dans une VM, prévoyez comme si votre jeu de travail rapide ne faisait que quelques mégaoctets.
  3. Plus de RAM n'est pas une RAM plus rapide. De 1 Mo à 256 Mo, le coût par lecture est multiplié par huit environ. Des gigaoctets en plus apportent de la capacité, pas de la vitesse ; ce qui accélère une tâche limitée par la latence, c'est un jeu chaud plus petit, comme le montre le partitionnement de Pivot.

Ce que cela change si vous louez des serveurs

  • Les serveurs cloud conviennent à la plupart des applications web, API et petites bases : leurs données chaudes tiennent en cache, et ils attendent le réseau ou le disque bien avant la RAM. Dimensionnez-les sur l'usage mémoire mesuré, comme dans notre guide de dimensionnement des serveurs cloud.
  • Les serveurs dédiés sont rentables quand un grand jeu de travail est lu au hasard toute la journée : analytique, grosses jointures de hachage, caches en mémoire, un serveur PostgreSQL dont les index ne tiennent plus en RAM. Vous avez tout le L3 et tous les canaux mémoire sans voisins, et vous pouvez activer les huge pages, qui réduisent les défauts de TLB. Configurez-en un sur la page serveur dédié.
  • Avant toute mise à niveau, lancez le test sur le serveur que vous avez déjà et vérifiez si votre tâche lente est limitée par la latence. Doubler les cœurs n'aide pas un thread bloqué la moitié du temps. La mémoire a elle-même renchéri cette année, voir RAM serveur en 2026 ; la solution la moins chère est souvent un code qui en touche moins.

Testez avant d'acheter

Nos data centers Tier III de Prague et Covilha proposent des serveurs cloud et des serveurs dédiés. Lancez un serveur cloud, exécutez memlat.js à côté de votre propre charge et envoyez le résultat à sales@dcxv.com : nous vous aiderons à décider si un serveur dédié changerait les chiffres.

10 000 avis en conseils municipaux US : ce qu'ils annoncent
clouddedicatedinfrastructure

10 000 avis en conseils municipaux US : ce qu'ils annoncent

Un jeu de données code 10 202 prises de parole sur les datacenters aux États-Unis : 90,5% contre, l'eau en tête. Nous recomptons et expliquons l'impact client.

Latence mémoire d'un serveur cloud : mesurée, pas devinée
clouddedicatedinfrastructure

Latence mémoire d'un serveur cloud : mesurée, pas devinée

Un article viral dit qu'un CPU occupé attend souvent la RAM. Nous avons mesuré la latence de L1 à la DRAM sur notre serveur cloud et expliquons ce qui change.

Altman veut votre DRAM au data center : RAM serveur 2026
cloudaipricinginfrastructure

Altman veut votre DRAM au data center : RAM serveur 2026

Sam Altman juge que la mémoire des PC dort et doit aller au data center. Ce que la pénurie de DRAM de 2026 change pour vos serveurs, et un script pour mesurer.

PHP2Shell : vérifier et corriger les failles RCE de PHP
clouddedicatedhosting

PHP2Shell : vérifier et corriger les failles RCE de PHP

PHP2Shell (CVE-2026-109618, CVE-2026-109619) permet à une requête non authentifiée d'exécuter du code dans PHP. Versions corrigées, script testé, parades php.ini, plan.

Brotli CVE-2026-111497 : corriger Node.js, Bun et Python
cloudnetworkinginfrastructure

Brotli CVE-2026-111497 : corriger Node.js, Bun et Python

Une faille du décodeur Brotli (CVE-2026-111497) exécute du code via fetch() dans Node.js et Bun ou les clients HTTP Python. Versions corrigées, script testé, rebuild.