Aller au contenu principal

25 articles tagués avec « Systèmes distribués »

Articles sur l'architecture et la conception des systèmes distribués.

Voir tous les tags

Des structures de données qui se répliquent : hashes, listes, sets et sorted sets dans Zaris

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

Hashes, listes, sets et sorted sets natifs, répliqués comme toute autre clé dans Zaris

Zaris 1.x stockait des valeurs. Zaris 2.0.0 stocke des collections. Les hashes, listes, sets et sorted sets sont désormais des types de premier ordre, côté serveur, assortis de véritables API .NET typées — et, tout aussi important, ils se comportent comme tout le reste dans le store.

C'est cette dernière partie que l'on se représente généralement de travers. Dans beaucoup de systèmes, les « structures de données » sont une illusion côté client : une bibliothèque sérialise un dictionnaire en un blob, le Put, et appelle cela un hash. Cela fonctionne jusqu'à ce que deux clients touchent la même collection en même temps, ou jusqu'à ce que vous demandiez ce qui se passe lors d'un basculement. Dans Zaris, un hash est un hash sur le serveur. Il réside sur la partition propriétaire de sa clé, il se réplique vers le réplica de cette partition, et il survit à la perte d'un nœud exactement comme le fait une simple clé.

Zaris 2.0.0 : structures de données natives, Streams et un front-end protocole-Redis

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

Zaris 2.0.0 — Structures de données natives, Streams et un front-end protocole-Redis

Aujourd'hui, nous publions Zaris 2.0.0 — la plus importante version depuis que Zaris a atteint la disponibilité générale, et la première avec un changement de version majeure. Elle transforme Zaris, qui était un store clé-valeur rapide et répliqué, en un serveur de structures de données complet : hashes, listes, sets, sorted sets, pub/sub et Redis Streams natifs, tous partitionnés et répliqués de la même façon que le sont déjà vos clés.

Et elle ouvre la porte à tous les autres. Chaque nœud peut désormais exposer un front-end protocole-Redis (RESP), de sorte qu'une application en Python, Ruby, Java, Go — n'importe quel langage disposant d'un client Redis — peut pointer vers Zaris et l'utiliser en remplacement direct, sans SDK natif et sans réécrire une ligne.

Le numéro de version est un 2, et non un 1.x, pour une raison : la 2.0.0 modifie le protocole filaire. Lisez la note de mise à niveau ci-dessous avant de la déployer.

Zaris 0.9.0 est là — et disponible en disponibilité générale

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

Zaris 0.9.0 — Disponibilité générale

Aujourd'hui, nous publions Zaris 0.9.0, et avec lui, Zaris atteint la disponibilité générale. Il est prêt pour la production, multiplateforme, et désormais soutenu par un support commercial.

Si vous ne le connaissez pas encore : Zaris est un store clé-valeur distribué et en mémoire pour .NET. Il est rapide, répliqué, et vous pouvez le piloter depuis un navigateur, PowerShell, ou directement depuis votre application. Cette version est l'aboutissement de ce travail — le moment où un « projet prometteur » devient une « solution que vous pouvez mettre en production ».

Les verrous distribués expliqués

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

Un guide pratique pour les développeurs .NET

Introduction​

À mesure que les applications montent en charge sur plusieurs machines, la coordination devient l'un des aspects les plus délicats de la conception des systèmes.

Dans une application mono-machine, l'exclusion mutuelle est simple. Les développeurs peuvent s'appuyer sur des primitives du langage telles que lock en C#, Mutex ou Semaphore pour garantir qu'un seul thread accède à une ressource partagée à la fois.

Cependant, ces primitives ne fonctionnent qu'au sein d'un seul processus ou d'une seule machine.

Dès lors que les applications s'exécutent sur plusieurs services ou nœuds, les mécanismes de verrouillage traditionnels ne fonctionnent plus. Deux services s'exécutant sur des machines différentes ne peuvent pas s'appuyer sur une instruction lock locale pour coordonner l'accès à un état partagé.

C'est ici que les verrous distribués deviennent essentiels.

Les verrous distribués permettent aux services répartis sur un cluster de coordonner l'accès aux ressources partagées tout en garantissant qu'un seul participant détient le verrou à un instant donné.


Verrous locaux vs verrous distribués​

Un verrou local typique en C# ressemble à ceci :

private static readonly object _lock = new object();

public void ProcessOrder()
{
lock(_lock)
{
Console.WriteLine("Processing order safely.");
}
}

Cela fonctionne parfaitement à l'intérieur d'un seul processus.

Cependant, si votre application s'exécute sur plusieurs instances de service, chaque instance possède son propre objet _lock. Le verrou ne coordonne plus le travail à l'échelle du système.

Worker A → lock acquired Worker B → lock acquired Worker C → lock acquired

Tous les workers progressent simultanément, ce qui annule l'intérêt du verrouillage.

Les systèmes distribués nécessitent un mécanisme de coordination partagé.


Verrouillage distribué


L'idée derrière les verrous distribués​

Un verrou distribué utilise un système partagé pour représenter la possession du verrou.

Au lieu de verrouiller la mémoire, un nœud enregistre la possession du verrou dans un système de coordination distribué tel que :

  • un store clé-valeur distribué
  • un service de coordination
  • un cache distribué

Concept d'exemple :

Lock Key: order:123 Owner: worker‑1

Si un autre worker tente d'acquérir le même verrou, l'opération échoue jusqu'à ce que le verrou soit libéré ou expire.


Scénario concret : traitement distribué de factures​

Imaginez un cluster de workers traitant des factures.

Worker A Worker B Worker C

Tous les workers recherchent les factures en attente.

Sans verrouillage :

Worker A → processes invoice #101 Worker B → processes invoice #101 Worker C → processes invoice #101

La même facture pourrait être traitée plusieurs fois.

Un verrou distribué garantit qu'un seul worker traite la facture.


Les verrous distribués avec Clustron DKV​

Clustron DKV fournit des primitives intégrées pour la coordination distribuée.

Les verrous sont gérés via l'API Locks, et les opérations sur les clés verrouillées doivent inclure le bon handle de verrou.


Acquérir un verrou​

Un client acquiert d'abord un verrou pour une clé spécifique.

var locks = ((IDkv)client).Locks;

var key = "order:123";

var lockHandle = await locks.AcquireAsync(key, TimeSpan.FromSeconds(10));

if (lockHandle == null)
{
Console.WriteLine("Failed to acquire lock.");
return;
}

Console.WriteLine("Lock acquired.");

Le handle de verrou renvoyé représente la possession du verrou.


Effectuer des opérations sous le verrou​

Une fois un verrou acquis, les opérations doivent inclure le handle de verrou.

var result = await client.PutAsync(
key,
"processed",
Put.WithLock(lockHandle.Handle));

if (result.IsSuccess)
{
Console.WriteLine("Value updated safely.");
}

Seul le propriétaire du verrou peut modifier la valeur.


Lire avec le verrou​

Les lectures peuvent elles aussi respecter la possession du verrou.

var value = await client.GetAsync<string>(
key,
Get.WithLock(lockHandle.Handle));

if (value.IsSuccess)
{
Console.WriteLine($"Value: {value.Value}");
}

Opérations concurrentes sans le verrou​

Si un autre worker tente de modifier la clé sans le verrou, l'opération échoue.

var attempt = await client.PutAsync(key, "new-value");

if (!attempt.IsSuccess)
{
Console.WriteLine($"Operation rejected: {attempt.Status}");
}

Résultat :

KvStatus.Locked

Cela empêche la modification concurrente de la même ressource.


Libérer le verrou​

Une fois le travail terminé, le verrou peut être libéré.

await lockHandle.ReleaseAsync();

Console.WriteLine("Lock released.");

Après la libération du verrou, un autre worker peut l'acquérir.


Exemple de workflow de cluster​

Worker A → Acquire Lock → Success Worker B → Acquire Lock → Failed Worker C → Acquire Lock → Failed

Worker A → Update Key Worker A → Release Lock

Un seul worker effectue l'opération, garantissant la correction.


Gérer les défaillances​

Les verrous dans Clustron sont bornés dans le temps.

Lors de l'acquisition d'un verrou, une durée doit être spécifiée :

await locks.AcquireAsync(key, TimeSpan.FromSeconds(10));

Si le client détenant le verrou s'arrête brutalement ou se déconnecte, le verrou finit par expirer, ce qui permet à un autre worker de l'acquérir.

Cela évite que les verrous ne restent détenus indéfiniment.


Bonnes pratiques​

Lorsque vous implémentez des verrous distribués :

  • Gardez les sections critiques courtes
  • Évitez les verrous globaux lorsque c'est possible
  • Partitionnez les verrous par ressource
  • Concevez toujours en prévoyant les scénarios de défaillance

En conclusion​

Les verrous distribués sont l'une des primitives de coordination les plus fondamentales des systèmes distribués.

Ils permettent aux services s'exécutant sur plusieurs machines de coordonner en toute sécurité l'accès aux ressources partagées tout en préservant la correction du système.

Des plateformes comme Clustron DKV simplifient cela en fournissant des primitives de verrouillage intégrées, des opérations atomiques et de fortes garanties de cohérence.

Dans le prochain article, nous explorerons une autre primitive essentielle des systèmes distribués :

l'élection de leader.

Concevoir des systèmes distribués

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

Un guide pratique pour les développeurs .NET

Introduction​

La plupart des systèmes backend commencent leur existence sur une seule machine.

Une application ASP.NET Core traite les requêtes, une base de données stocke les données applicatives et des workers d'arrière-plan gèrent les tâches asynchrones telles que l'envoi d'e-mails ou la génération de rapports. Dans cet environnement, la concurrence reste gérable et la coordination entre les composants est relativement simple.

À mesure que le système grandit, cependant, les choses commencent à changer.

Le trafic augmente, davantage d'instances applicatives sont déployées derrière un load balancer et les services s'exécutent sur plusieurs machines. Ce qui était autrefois une application unique évolue vers un système distribué.

À ce stade, la nature du problème change radicalement.

Les défis ne se limitent plus à l'écriture d'une logique métier correcte. Les développeurs doivent désormais composer avec la coordination entre machines, les pannes réseau, les défaillances partielles et le maintien de la cohérence sur un état distribué.

C'est ici que commence l'ingénierie des systèmes distribués.


Architecture des systèmes distribués


Qu'est-ce qu'un système distribué ?​

Un système distribué est un ensemble d'ordinateurs indépendants qui apparaissent à l'utilisateur comme un système cohérent unique.

Au lieu d'exécuter toute la logique sur une seule machine, les responsabilités sont réparties sur plusieurs nœuds qui communiquent par le réseau.

En voici quelques exemples :

  • Les architectures microservices
  • Les bases de données distribuées
  • Les caches en cluster
  • Les files de messages
  • Les plateformes d'infrastructure cloud

Ces systèmes offrent évolutivité et résilience, mais introduisent de nouvelles complexités.


Pourquoi les systèmes distribués sont difficiles​

Contrairement à une application mono-machine, les systèmes distribués doivent composer avec des réalités telles que :

Les pannes réseau​

Dans les systèmes distribués, la communication passe par un réseau. Les réseaux peuvent être lents, peu fiables ou temporairement indisponibles.

Une requête peut échouer parce que le nœud distant s'est arrêté brutalement, parce que le réseau a perdu des paquets ou parce qu'un timeout s'est produit.

Le système doit gérer ces scénarios avec élégance.


Les défaillances partielles​

Dans un système distribué, les composants peuvent tomber en panne indépendamment les uns des autres.

Un nœud d'un cluster peut s'arrêter brutalement tandis que les autres restent sains. Une instance de service peut redémarrer pendant que d'autres services continuent de fonctionner.

Cela signifie que le système doit fonctionner correctement même lorsqu'une partie seulement de celui-ci est opérationnelle.


Les défis de cohérence​

Lorsque des données sont répliquées sur plusieurs nœuds, les maintenir cohérentes devient difficile.

Par exemple :

  • Deux nœuds peuvent tenter de mettre à jour la même donnée simultanément.
  • Les délais réseau peuvent amener des nœuds à être temporairement en désaccord sur l'état courant.
  • Un nœud peut s'arrêter brutalement après n'avoir exécuté qu'une partie d'une opération.

Concevoir des systèmes qui maintiennent un état cohérent malgré ces scénarios exige une coordination minutieuse.


Briques fondamentales des systèmes distribués​

La plupart des systèmes distribués reposent sur quelques primitives essentielles.

Comprendre ces primitives aide les développeurs à concevoir des architectures fiables.


Le stockage distribué​

Les données doivent souvent être stockées sur plusieurs machines.

Cela permet :

  • la mise à l'échelle horizontale
  • la tolérance aux pannes
  • la haute disponibilité

Les stores clé-valeur distribués sont couramment utilisés à cette fin.


La coordination​

Les nœuds doivent coordonner des actions telles que :

  • l'élection de leader
  • le verrouillage distribué
  • l'appartenance au cluster
  • les mises à jour de configuration

Sans mécanismes de coordination, plusieurs nœuds pourraient tenter des opérations conflictuelles.


Le consensus​

Certains systèmes exigent de fortes garanties sur l'état partagé.

Les algorithmes de consensus tels que Raft ou Paxos permettent aux nœuds de s'accorder sur des décisions même en présence de défaillances.

Ces algorithmes sont fondamentaux pour les bases de données distribuées et les services de coordination.


Le partitionnement et la réplication​

Les données sont généralement :

  • partitionnées entre les nœuds pour répartir la charge
  • répliquées pour se protéger contre les défaillances

Équilibrer performance, disponibilité et cohérence est l'un des défis de conception fondamentaux.


Modèles courants des systèmes distribués​

Plusieurs modèles reviennent régulièrement dans les systèmes réels.

En voici quelques exemples :

  • L'élection de leader pour coordonner les activités du cluster
  • Les verrous distribués pour garantir l'exclusion mutuelle
  • Les files de tâches pour le traitement asynchrone
  • Les limiteurs de débit pour contrôler le volume de requêtes
  • Les protocoles de transaction pour les mises à jour atomiques multi-nœuds

Ces modèles constituent le socle de nombreuses plateformes à grande échelle.


Le rôle des systèmes de coordination​

Pour simplifier le développement distribué, de nombreuses organisations s'appuient sur des systèmes de coordination tels que :

  • etcd
  • ZooKeeper
  • Consul

Ces systèmes fournissent des primitives telles que :

  • l'élection de leader
  • les verrous distribués
  • l'appartenance au cluster
  • le stockage de configuration

Les applications peuvent alors construire des comportements de plus haut niveau par-dessus ces primitives.


Les systèmes distribués dans l'écosystème .NET​

Bien que les outils d'infrastructure distribuée soient souvent associés à d'autres écosystèmes, les applications .NET opèrent de plus en plus dans des environnements distribués.

Les systèmes .NET modernes utilisent fréquemment :

  • Kubernetes
  • des caches distribués
  • des microservices
  • des architectures pilotées par les événements

En conséquence, la coordination et la gestion de l'état distribué deviennent de plus en plus importantes pour les développeurs .NET également.


En conclusion​

Concevoir des systèmes distribués est fondamentalement différent de concevoir des applications mono-machine traditionnelles.

Les défis de la communication réseau, des défaillances partielles et de la cohérence des données introduisent des complexités qui exigent des modèles et une infrastructure spécialisés.

Heureusement, en comprenant les briques fondamentales — stockage, coordination, consensus et réplication — les développeurs peuvent concevoir des systèmes qui montent en charge de façon fiable et restent résilients face aux défaillances.

Dans de prochains articles, nous explorerons certaines de ces primitives plus en détail, notamment l'élection de leader, les modèles de coordination distribuée et les implémentations pratiques en .NET.