Aller au contenu principal

Échouer en se fermant, jamais de façon destructive : au cœur du cycle de vie des licences Zaris

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

Le cycle de vie des licences Zaris

Les licences sont la partie d'un produit à laquelle la plupart des ingénieurs ne veulent jamais penser, et cela se voit. Le schéma habituel est une bombe à retardement : une date est vérifiée, et quand elle passe, le logiciel vous punit — il lève une exception au démarrage, il corrompt ou efface l'état local pour vous empêcher de le « voler », ou il plante simplement et emporte vos données avec lui. Cette conception traite vos propres opérateurs en adversaires, et elle échoue exactement au moment où vous pouvez le moins vous le permettre : en production, après que l'horloge a silencieusement basculé.

Zaris adopte la posture inverse. La vérification de licence est l'interrupteur le plus critique pour la sûreté d'un store de données distribué, alors elle est construite comme tel : une unique fonction de politique pure et déterministe, un chemin d'application gracieux et entièrement réversible qui ne détruit jamais un octet, et une horloge par machine qui reprend à l'instant où vous activez une clé. Cet article parcourt le fonctionnement réel de ce cycle de vie dans le code livré — car l'ingénierie intéressante ici réside dans ce qu'il refuse de vous faire subir.

Tout ou rien : les transactions multi-clés dans Zaris

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

Les transactions multi-clés dans Zaris

Un article compagnon, Coordination sans course sur le CAS optimiste, a défendu l'idée qu'une primitive unique — une version possédée par le store plus une écriture conditionnelle gardée par la version — porte une quantité remarquable de coordination. Il a aussi tracé une ligne nette : le CAS est atomique sur une clé. Transférez de l'argent du compte A vers le compte B et un seul compare-and-swap ne peut pas couvrir les deux ; le conseil honnête était de modéliser le transfert comme une machine à états sur une clé, ou de recourir à une saga.

Cette ligne est réelle, mais ce n'est pas toute l'histoire. Zaris dispose d'une véritable transaction multi-clés — BeginTransactionAsync, un ensemble de lecture/écriture mis en attente, CommitAsync — et elle commite à travers les clés et à travers les nœuds avec une garantie du tout ou rien. Cet article porte sur ce qu'est réellement cette transaction sous le capot (un commit à deux phases coordonné par le client sur des versions optimistes), précisément ce qu'elle garantit, et la seule subtilité qui décide si votre invariant inter-clés tient réellement.

Les tentatives que vous n'écrivez pas : survivre au changement de propriété dans le client Zaris

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

Nouvelle tentative et redirection transparentes lors d'un changement de propriété

Voici un fait concernant tout store clé-valeur partitionné que les schémas léchés ont tendance à passer sous silence : le nœud qui possède votre clé va se déplacer. Un nœud tombe en panne et ses partitions basculent vers leurs réplicas. Vous montez en charge et les partitions migrent vers le nouveau membre. Un primaire préféré revient et la propriété lui est rendue. Chacun de ces événements signifie que le nœud auquel votre client parlait tranquillement il y a une milliseconde est, à l'instant présent, le mauvais nœud pour un certain ensemble de clés.

L'expérience client naïve de ce moment est désagréable : une connexion réinitialisée, une « erreur serveur » générique ou — pire — une écriture qui atterrit sur un nœud qui n'est plus le propriétaire actif et qui, discrètement, ne mène nulle part. Le client Zaris .NET est conçu pour que rien de tout cela n'atteigne votre code. Un changement de propriété devient un statut typé, le client redirige vers le nouveau propriétaire, et la nouvelle tentative est bornée à la fois par un budget de tentatives et par une échéance en temps réel. Dans le cas courant, votre PutAsync prend simplement quelques millisecondes de plus et renvoie Ok. Cet article traite de la mécanique qui rend cela vrai et — tout aussi important — des cas qu'elle choisit délibérément de ne pas masquer.

Un journal, deux missions : comment un réplica et un nouveau propriétaire se mettent à jour de la même façon

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

Se mettre à jour en rejouant le journal — un seul journal d'opérations ordonné par révision alimente aussi bien les réplicas que les nouveaux propriétaires

Deux événements d'apparence très différente dans un store distribué s'avèrent être le même problème en dessous. Le premier : un réplica prend du retard sur son primaire — une pause de ramasse-miettes, un disque lent, une brève partition réseau — et détient désormais une copie périmée d'une partition qu'il doit finir par faire correspondre. Le second : une partition est réassignée à un nœud qui ne l'a jamais détenue, et ce nœud doit acquérir l'ensemble complet des données auprès du propriétaire actuel. L'un est un retard de réplication ; l'autre est une migration. Ils ont des déclencheurs différents, des opérateurs différents, des histoires d'échec différentes.

Mais la question à laquelle chacun doit répondre est identique : comment converger vers la vérité courante de cette partition sans geler les écritures pendant que je le fais ? Zaris répond aux deux avec un seul mécanisme — un journal d'opérations ordonné par révision, tenu par segment, rejoué depuis un point connu. Cet article porte sur ce journal : comment il est construit sur le chemin d'écriture, comment il est borné pour ne pas pouvoir grossir sans limite, comment il est rejoué, et pourquoi exactement le même substrat conduit à la convergence tant un réplica en retard qu'un propriétaire flambant neuf.

Une primitive, de nombreuses garanties : coordination sans course sur le CAS optimiste

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

Coordination sans course sur le CAS optimiste de Zaris

Il est tentant de juger un store de données à la longueur de sa liste de commandes. Redis a INCR, SETNX, MULTI/EXEC, WATCH, Lua, SCAN, pub/sub — un verbe pour chaque occasion. Le client .NET de Zaris, en comparaison, paraît presque austère. Il n'y a pas d'incrément atomique côté serveur. Il n'y a pas de transaction multi-clés générale qui exécute une logique arbitraire. Il n'y a pas de scan de préfixe. Le pub/sub natif n'existe qu'à travers le front-end RESP, pas le client .NET typé.

Ce que le client .NET vous donne à la place est une petite primitive de coordination tranchante : le compare-and-swap versionné optimiste. Cet article porte sur la distance que parcourt réellement cette seule primitive — car la réponse honnête est : étonnamment loin. Un limiteur de débit, un portefeuille qui ne devient jamais négatif sous un millier de débits concurrents, une file de jobs où exactement un worker revendique chaque job, et un jeu de règles de feature-flag qui ne perd jamais une mise à jour sous des éditions d'administration concurrentes. Tous, à partir de la même primitive, sans machinerie supplémentaire côté serveur.

Clustron Zaris 2.0.1 : durable par défaut, licencié en une ligne

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

Clustron Zaris 2.0.1 — durable par défaut, licencié en une ligne

Zaris 2.0.1 est disponible. C'est une mise à niveau transparente depuis la 2.0.0 — même protocole de communication, même API cliente, mêmes formats sur disque et en mémoire — et elle fait deux choses qui valent la mise à niveau : elle rend le chemin de propriété et de récupération du cluster nettement plus durable en cas de panne, et elle dote Zaris d'un modèle d'essai et de licence intégré et propre, afin que vous puissiez l'évaluer et l'exécuter en production sans friction.

Aucune écriture acquittée laissée pour compte : l'épine dorsale de propriété et de récupération sous 12 heures de chaos

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

Zéro perte d'écriture acquittée, prouvé sur 12 heures de chaos

Le chemin heureux d'un store clé-valeur distribué est facile à réussir. Une écriture atterrit sur le primaire, se diffuse vers les réplicas, tout le monde est d'accord, vous passez à la suite. Si c'était toute l'histoire, la durabilité serait un problème résolu et cet article n'existerait pas.

Les problèmes difficiles vivent dans les coutures — ces moments brefs et maladroits où le cluster est en pleine transition. Un nœud redémarre au milieu d'une migration de partition. Un réplica prend beaucoup de retard sur le primaire actif qu'il copie, puis ce primaire bascule vers quelqu'un d'autre. La propriété d'une partition se déplace vers un nouveau nœud alors que des écritures sont encore en vol vers l'ancien. Chacun de ces cas est une fenêtre : une période de quelques secondes où, si le transfert n'est pas exactement correct, une écriture acquittée — une écriture dont on a dit au client qu'elle avait réussi — peut disparaître discrètement. Non pas parce que le moteur de stockage est bogué, mais parce que deux parties du système se sont contredites, un instant, sur qui possédait la vérité.

Cet article traite de la façon dont Zaris ferme ces fenêtres et — la partie qui compte réellement — de la façon dont nous nous sommes convaincus que cela fonctionne, en exécutant le cluster sous un chaos continu et délibéré pendant douze heures d'affilée.

Chemins chauds sans allocation : comment le client .NET de Zaris utilise ValueTask

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

Le client .NET de Zaris utilise ValueTask sur ses opérations de chemin chaud

La plupart du temps, Task<T> est exactement le bon type de retour pour une méthode asynchrone, et vous ne devriez pas y réfléchir à deux fois. Mais il y a un endroit précis où il vous coûte discrètement : un chemin chaud qui se termine de façon synchrone, appelé des millions de fois.

Voici le mécanisme. Task<T> est un type référence. Chaque appel qui en renvoie un alloue un objet Task sur le tas — même lorsque l'opération se termine de façon synchrone. Un succès de cache servi directement depuis un tampon local, un awaitable déjà terminé : rien de tout cela ne requiert une vraie asynchronie, mais vous payez quand même un objet sur le tas pour porter le résultat. Une allocation n'est rien. Au rythme d'appel d'un client à haut débit — une boucle serrée effectuant des millions de petits Get et Put — c'est un flux régulier de petites allocations sur le tas, et ce flux alimente le ramasse-miettes. Plus de collectes gen-0, plus de CPU dépensé en ramasse-miettes au lieu de votre travail, plus de gigue dans vos latences de queue.

Le client .NET de Zaris s'attaque à cela exactement là où ça compte et nulle part ailleurs. Cet article porte sur cette décision : quelles méthodes ont changé, pourquoi, les règles que vous devez suivre pour les utiliser correctement, et — délibérément — quelles méthodes nous avons laissées intactes.

Grandes valeurs, petites pauses : le découpage des gros objets dans Zaris

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

Le découpage des gros objets maintient les grandes valeurs hors du LOH

Il y a un nombre que tout ingénieur performance .NET finit par mémoriser : 85 000 octets. Toute allocation unique au-delà d'environ cette taille ne va pas sur le tas normal des petits objets — elle va sur le Large Object Heap (LOH). Le LOH est une autre bête. Il n'est collecté que lors d'un ramasse-miettes gen-2 (complet), et par défaut il n'est pas compacté. Cette combinaison convient à un gros tampon que vous allouez une fois et conservez. Elle ne convient pas à un store en mémoire à faible latence qui écrit et réécrit à répétition de grandes valeurs.

Imaginez la charge de travail : gros blobs sérialisés, grands documents JSON, images, charges utiles de protocole — stockés, mis à jour, remplacés, encore et encore. Chacune de ces grandes écritures dépose un objet neuf sur le LOH. Comme le LOH n'est pas compacté, les emplacements libérés ne fusionnent pas en espace contigu ; ils se fragmentent. Et comme en récupérer la moindre partie implique un ramasse-miettes gen-2 complet, les pauses s'allongent et surviennent plus souvent précisément à mesure que l'ensemble de travail grossit. Pour un store dont tout l'argumentaire est la faible latence, c'est le mauvais type de surprise.

Zaris propose une fonctionnalité optionnelle pour contourner entièrement le LOH pour ces valeurs. Elle est désactivée par défaut, et cet article porte sur ce qu'elle fait, comment elle fonctionne, et — tout aussi important — quand vous devriez et ne devriez pas l'activer.

Mise à l'échelle élastique : ajouter et retirer des serveurs Zaris sans interruption

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

Agrandir et réduire un store Zaris en direct sous un superviseur

La capacité n'est jamais juste longtemps. Le trafic augmente, un lancement a lieu, une saison se termine — et le store que vous avez dimensionné le trimestre dernier est soit saturé, soit à moitié inactif. La question qui décide si c'est une corvée ou une crise est simple : pouvez-vous changer la taille d'un store en cours d'exécution sans l'arrêter ?

Pour Zaris la réponse est oui, avec une asymétrie importante qu'il vaut la peine d'avouer d'emblée. La mise à l'échelle horizontale — ajouter des serveurs — est la direction facile, sûre et sans perte, et elle se produit en direct pendant que le store continue de servir. La réduction d'échelle — retirer des serveurs — est également prise en charge, mais c'est une opération délibérée et surveillée, car les données du serveur qui part doivent d'abord aller quelque part.

Cet article parcourt les deux directions : agrandir un store avec Add-ZrServer, le réduire avec Remove-ZrServer, pourquoi la réduction nécessite un drain, et où s'insère la console web.