Aller au contenu principal

Des lectures qui montent en charge avec vos cœurs

· 6 minutes de lecture
Clustron Team
Ingénierie des systèmes distribués

Le débit GET de Zaris monte en charge avec les cœurs

Redis est rapide. Il est aussi, par conception, mono-thread sur le chemin de données : une boucle d'événements, un cœur, une commande à la fois. C'est une conception réellement bonne — elle rend Redis simple à appréhender et élimine toute une catégorie de bugs de concurrence. Mais elle comporte un plafond qu'aucune somme d'argent ne peut lever. Donnez à un moteur mono-boucle d'événements une machine à 4 cœurs, à 8 cœurs, à 32 cœurs, et le débit en lecture retombe au même endroit. Les cœurs supplémentaires restent inactifs.

Zaris emprunte l'autre voie. Les clés sont partitionnées et chaque partition a un propriétaire, de sorte que les lectures de clés différentes atterrissent sur des cœurs différents et s'exécutent en même temps. Résultat : un débit qui bouge lorsque vous ajoutez des cœurs — une pente plutôt qu'une ligne plate.

Les chiffres​

Nous avons mesuré le débit GET à travers le front-end RESP de Zaris — le même chemin protocole-Redis qu'emprunterait un client Redis ordinaire — face à Redis et Memurai sur le même matériel.

Moteur1 cœur4 cœurs
Zaris (RESP GET)~483 000 ops/s~946 000 ops/s
Redis / Memurai~740–780 000 ops/s~740–780 000 ops/s (plat)

Deux choses sont vraies ici, et nous voulons être francs sur les deux.

D'abord, la mise en garde honnête : passer de 1 cœur à 4 cœurs double à peu près le débit de Zaris, il ne le quadruple pas. Cela représente environ 0,5 d'efficacité de mise à l'échelle — sous-linéaire. La coordination inter-cœurs, la bande passante mémoire et le chemin réseau prennent tous leur part. Quiconque vous dit qu'un store distribué monte en charge de façon parfaitement linéaire vous vend quelque chose.

Ensuite, ce qui compte : Zaris grimpe, et un moteur mono-boucle d'événements en est incapable. À un cœur, Redis et Memurai sont en réalité devant — une boucle mono-thread serrée sans coordination inter-cœurs est difficile à battre sur un seul cœur. Mais ce chiffre est aussi leur plafond. Zaris démarre plus bas et les dépasse à mesure que les cœurs entrent en jeu, parce que le travail est véritablement parallèle. Sur une grosse machine moderne, « monte en charge à 0,5 d'efficacité » bat « cloué à un seul cœur » à chaque fois.

Pourquoi cela monte en charge​

Une boucle d'événements unique sérialise tout : chaque GET, chaque SET, chaque client, canalisés par un seul thread. C'est compatible avec le cache et sans verrou, mais c'est fondamentalement l'équivalent du travail d'un seul cœur.

Zaris, lui, donne à chaque partition un propriétaire et répartit le travail par cœur. Deux clients lisant deux clés qui résident dans des partitions différentes ne touchent jamais le même thread. Ajoutez des cœurs, ajoutez des partitions, et davantage de ces lectures s'exécutent simultanément.

Et il n'y a aucune taxe de proxy à payer pour cela. Zaris hache les clés avec le même calcul de slot CRC16(key) % 16384 qu'utilise Redis Cluster, de sorte qu'un client Redis conscient du cluster achemine chaque clé directement vers le nœud qui la possède :

redis client ──CRC16(key) % 16384 → slot → owner──▶ node that holds the key ──▶ reply

C'est un seul saut, exactement comme avec Redis Cluster — le client hache la clé et se connecte directement à son propriétaire, et lorsque la commande y atterrit, elle est servie depuis le store intra-processus de ce nœud. Ce que vous gagnez par rapport à une instance unique, c'est une capacité de lecture qui croît avec le cluster au lieu de plafonner sur un seul cœur, sans renoncer au routage direct-vers-le-propriétaire pour l'obtenir.

Le chemin d'écriture est devenu plus rapide lui aussi​

La 2.0.0 ne concernait pas que les lectures. Sur le chemin SET, nous avons supprimé une lecture-avant-écriture que chaque écriture payait, et corrigé un appel Count() parasite sur le chemin critique qui avait discrètement plafonné le débit SET. Sur le client .NET natif, les opérations du chemin critique — Get, Put, Delete, Expire, Persist, Ttl, et leurs formes chaînées — renvoient désormais un ValueTask, de sorte qu'un appel qui se termine de façon synchrone n'alloue rien :

// Alloc-free when the value is already local — no Task on the fast path.
ValueTask<ReadResult<Order>> pending = client.GetAsync<Order>("order:42");

Et pour les charges de travail aux valeurs volumineuses et fréquemment mises à jour, un mode optionnel de découpage des objets volumineux stocke les grosses valeurs chaudes sous forme de morceaux byte[][] inférieurs au LOH, les tenant à l'écart du Large Object Heap et hors de la trajectoire du ramasse-miettes.

Mesurez-le honnêtement​

Si vous réalisez ce benchmark vous-même, deux choses vous piégeront :

  • Les benchmarks de lecture sont généralement limités par le client. Un générateur de charge unique sature bien avant le serveur, et vous mesurez alors votre client, pas Zaris. Pour voir réellement le serveur monter en charge, il vous faut assez de charge concurrente — plusieurs générateurs, assez de connexions — pour occuper chaque cœur. Si le débit est plat à mesure que vous ajoutez des cœurs serveur, vérifiez d'abord si c'est votre client qui est le goulot d'étranglement.
  • Mesurez correctement le CPU du serveur. Lisez-le depuis le cgroup, pas depuis une estimation d'un metrics-server de cluster. L'estimation est en retard et lissée, et elle vous mentira sur la question de savoir si le serveur est réellement saturé.

Essayez-le​

dotnet add package Clustron.Zaris.SDK --version 2.0.0

Si vous pesez Zaris face à Redis pour une pile .NET, la comparaison Clustron vs Redis expose les arbitrages, et Zaris 2.0.0 couvre tout le reste de ce qui a été livré dans cette version — structures de données natives, Streams, et le front-end protocole-Redis qui a rendu ces chiffres mesurables en premier lieu. Si vous venez d'un déploiement Redis existant, Vous venez de Redis parcourt la migration, et l'analyse approfondie du protocole Redis explique en détail la conception du proxy.

Les téléchargements et les notes de version complètes sont sur GitHub, ou installez Zaris sur la plateforme de votre choix.