menuTicketing

Principe de fonctionnement


Acquisition et libération du verrou

Lorsqu'un client acquiert (A) une clé, le serveur répond de l'une des trois façons suivantes.

État de la cléAction du serveurRéponse
Non enregistréeEnregistrement immédiat (expiration = now + lease), délivrance d'un jetonA + token + key
Enregistrée + expiréeRenouvellement (now + lease), délivrance d'un nouveau jetonA + token + key
Enregistrée + valide (occupée)Ajout à la file d'attente, réponse différéeA lors de la libération/expiration, T si wait est dépassé
  • La libération est traitée équitablement en FIFO. Lorsque le détenteur libère (R) la clé, elle est transmise directement au premier de la file d'attente — la remise se fait immédiatement avec un nouveau jeton, sans nouvelle mise en concurrence.
  • Le lease est un filet de sécurité. Même si un client meurt ou oublie de libérer la clé, le serveur peut la récupérer automatiquement après l'écoulement du délai lease et la transmettre au demandeur suivant. Il est donc recommandé de toujours régler le lease, indépendamment du flux normal de libération, sur une valeur suffisamment large mais qui n'immobilise pas la clé trop longtemps en cas de mort du client.
  • wait est la limite d'attente pour l'acquisition. À 0, l'attente est illimitée ; sinon, si la clé n'est pas obtenue dans ce délai (en secondes), le serveur abandonne et répond par T (timeout) — l'opération se termine sans octroi, donc aucun verrou ne fuit.

Jeton de fencing

Le token contenu dans la réponse A est le u64 strictement croissant de cet octroi (grant). À chaque acquisition, une valeur supérieure à tout jeton précédent est délivrée. Même en cas de bascule (failover), le nœud nouvellement actif reprend la numérotation à partir d'une valeur supérieure au jeton maximal reçu par réplication (succession) — le jeton continue donc de croître sur l'ensemble du cluster.

Il suffit que la ressource à protéger (compte, fichier, commande, etc.) vérifie uniquement que « le jeton actuel est supérieur au dernier jeton observé » pour pouvoir refuser l'accès d'un client qui se réveille tardivement après l'expiration du lease avec un jeton faible désormais invalidé. Cela permet de préserver la sécurité même si le serveur de verrouillage n'est pas parfaitement cohérent à tout instant.

Comportement du client

Les clients officiels partagent le comportement commun suivant (pour l'API détaillée propre à chaque langage, consultez Bibliothèques).

  • Une connexion persistante est maintenue par adresse et gérée en arrière-plan. Si une seule adresse est fournie, deux connexions sont maintenues en interne vers le même nœud, afin que le service ne s'interrompe pas si l'une d'elles est momentanément coupée.
  • Les connexions sont choisies en round-robin. Un nœud dont la connexion est coupée est automatiquement exclu, et une tentative de reconnexion est effectuée en arrière-plan toutes les 3 secondes.
  • Les requêtes sont pipelinées. La requête suivante peut être envoyée sans attendre la réponse, et l'ordre des réponses peut différer de l'ordre des requêtes — le client identifie la requête associée à chaque réponse grâce à la combinaison (op, clé) renvoyée en écho. Si plusieurs requêtes partagent la même combinaison (op, clé), elles sont associées dans leur ordre d'envoi.
  • Si la connexion est coupée pendant une tentative d'acquisition, le client bascule automatiquement vers la connexion suivante. Ce n'est que si aucune connexion utilisable ne reste après un nombre de tentatives égal au nombre de connexions enregistrées qu'une erreur est signalée.
  • La libération est retentée pendant 5 secondes à intervalles de 200 ms — de sorte que si la connexion est justement coupée au moment de la libération, le verrou ne reste pas indéfiniment sur le serveur (le lease finira par le récupérer, mais l'objectif est de le transmettre plus rapidement à un autre demandeur avant cela).

Cluster — continuité de service basée sur la priorité

  • L'ordre de la liste peers définit la priorité de promotion (le premier a la priorité la plus haute). Parmi les nœuds vivants, celui ayant la priorité la plus élevée devient actif, les autres devenant des standby qui reçoivent son état par réplication en temps réel.
  • Seul le nœud actif traite les requêtes des clients. Un client connecté à un standby est redirigé (M) vers l'adresse du nœud actif.
  • En cas de panne ou de redémarrage de l'actif, un standby est promu et prend le relais.
  • Lors d'un arrêt propre (graceful) (Ctrl+C), l'actif transmet d'abord la promotion à son successeur (handoff) avant de rediriger les clients, ce qui minimise la période sans nœud actif.
  • Rétrogradation automatique : si une partition réseau (ou autre cause) fait que deux nœuds deviennent actifs simultanément, celui dont la priorité est la plus basse détecte l'autre et se rétrograde de lui-même en standby (ce qui évite un split-brain permanent).

Ce mécanisme de promotion ne repose pas sur un quorum (vote majoritaire). Le nombre pair ou impair de nœuds n'a donc aucune importance, et le service est maintenu tant qu'un seul nœud reste vivant.

Nombre de serveursSans interruptionPannes simultanées toléréesRemarque
1Le plus rapide. Brève interruption lors du redémarrage
21Configuration minimale sans interruption. Suffisante dans la plupart des cas
32La redondance est maintenue même pendant la maintenance d'un nœud
4+N−1Seul le coût de propagation augmente — non recommandé

À propos de la cohérence

La promotion basée sur la priorité n'étant pas un consensus, les deux nœuds peuvent brièvement devenir actifs en même temps lors d'une partition réseau, et en raison de la nature asynchrone de la réplication, certains octrois (grant) peuvent être perdus au moment de la bascule. Autrement dit, l'exclusion mutuelle n'est pas garantie à 100 % pendant les périodes de bascule ou de partition. Si une garantie forte est nécessaire, implémentez la vérification du jeton de fencing décrit plus haut au niveau de la ressource protégée — en rejetant les jetons anciens (plus faibles), la sécurité est assurée même si le serveur de verrouillage n'est pas parfaitement cohérent.