Contexte et problème

Aria, le bus de messagerie interne de Jane Street, traite plusieurs téraoctets de données chaque jour. Les clients récupèrent les messages via TCP et, lorsqu’ils sont en retard, ils déclenchent une récupération du tip en lisant le tampon circulaire en mémoire. Cette opération filtrait l’ensemble du flux pour ne retenir que les sujets souscrits. Au départ, un simple passage linéaire suffisait : il était « cache‑friendly », mais l’augmentation du nombre de clients a conduit certains serveurs à atteindre 100 % d’utilisation CPU, provoquant des décrochages de clients.

Stratégie d’indexation par partitions

Pour éviter de parcourir l’intégralité du flux, l’équipe a introduit un index par partition de sujet. Une partition regroupe tous les sujets partageant le même préfixe à deux niveaux (ex. app/codestore). Chaque partition possède un index indiquant la position des messages dans le flux. Lors d’une requête, Aria réalise une fusion n‑way des index grâce à un min‑heap, reconstruisant ainsi le sous‑flux demandé dans l’ordre correct. Cette approche évite la création d’un index par sujet – qui aurait nécessité près d’un million d’index – et cible uniquement les partitions réellement sollicitées.

Optimisation du min‑heap et benchmark

Les premiers tests ont identifié le min‑heap comme le principal goulot d’étranglement. L’intern a fait appel à un agent d’IA pour générer et profiler cinq implémentations de tas pendant la nuit. L’implémentation fast_heap_unboxed a offert un gain de 2× sur le code de récupération indexée. En combinant cet amélioration avec l’indexation, la consommation CPU sur les charges de production a chuté de 30 % tout en conservant le niveau d’exactitude requis pour un système critique.

Gestion dynamique de la mémoire

Le stockage des index devait rester flexible. Un index complet pour les messages les plus petits (32 octets) aurait occupé jusqu’à 2 Go, ce qui est prohibitif pour chaque partition. La solution retenue est un pool partagé de blocs de 1024 entrées. Chaque index pointe vers un bloc et insère les positions de messages. Quand tous les messages d’un bloc quittent le tampon circulaire, le bloc est libéré et réutilisé par d’autres index. Cette stratégie garantit que la taille de l’index varie proportionnellement au nombre réel de messages, évitant ainsi une consommation mémoire excessive.