1 points par GN⁺ 2025-12-09 | Aucun commentaire pour le moment. | Partager sur WhatsApp
  • Jepsen a vérifié la durabilité et la cohérence du système de messagerie distribuée NATS JetStream dans divers environnements de défaillance
  • Les résultats des tests montrent qu’en cas de corruption de fichiers (.blk, snapshot) et de simulation de panne d’alimentation, on observe des pertes de données et des épisodes de split-brain
  • JetStream exécute fsync toutes les 2 minutes par défaut, si bien que des messages récemment acquittés peuvent rester non écrits sur disque
  • Une seule panne de système d’exploitation peut déjà provoquer des pertes de données et une incohérence de réplication
  • Jepsen recommande soit de changer la valeur par défaut de fsync en always, soit de documenter explicitement le risque de perte de données

1. Contexte

  • NATS est un système de streaming populaire permettant de publier et de s’abonner à des messages sous forme de flux
    • JetStream utilise l’algorithme de consensus Raft pour répliquer les données et garantit une livraison au moins une fois (at-least-once)
  • La documentation de JetStream affirme offrir une cohérence Linearizable et une disponibilité constante, mais selon le théorème CAP, ces deux propriétés ne peuvent pas être assurées simultanément
  • Selon la documentation NATS, un flux à 3 nœuds peut tolérer la perte d’1 serveur, et un flux à 5 nœuds peut tolérer celle de 2 serveurs
  • Un message est considéré comme « stocké avec succès » dès que le serveur a acquitté (acknowledge) la requête publish
  • La cohérence des données requiert un quorum (majorité) de nœuds, et dans un cluster à 5 nœuds il faut au minimum 3 nœuds opérationnels pour pouvoir stocker de nouveaux messages

2. Conception des tests

  • Jepsen a exécuté les tests avec le client JNATS 2.24.0 dans des conteneurs Debian 12 LXC
    • Certains tests utilisent l’image officielle NATS Docker dans un environnement Antithesis
  • Un flux JetStream unique (réplication 5) a été configuré, puis des arrêts forcés de processus, plantages, partitions réseau, pertes de paquets et corruptions de fichiers ont été injectés
  • Une simulation de panne d’alimentation a été réalisée avec le système de fichiers LazyFS pour provoquer la perte d’écritures non validées par fsync
  • Chaque processus publie un message unique, puis vérifie la présence des messages acquittés sur tous les nœuds à la fin du test
  • Si un message n’existe que sur certains nœuds, il est classé comme divergence (incohérence de réplication)

3. Principaux résultats

3.1 Perte totale de données sur NATS 2.10.22 (#6888)

  • Une perte totale du flux JetStream a été détectée avec un simple crash de processus
  • L’erreur "No matching streams for subject" apparaît, puis la situation ne se résout pas pendant plusieurs heures
  • La cause est liée à une inversion de snapshot du leader et à la suppression de l’état Raft, et le problème a été corrigé dans la version 2.10.23

3.2 Pertes de données en cas de corruption de fichiers .blk (#7549)

  • Lorsqu’un fichier .blk de JetStream subit une erreur de bit unique ou une troncature, des centaines de milliers d’écritures acquittées peuvent être perdues
    • Exemple : 679 153 pertes sur 1 367 069 messages
  • Même si seuls certains nœuds sont corrompus, des pertes massives de données et un split-brain peuvent se produire
    • Exemple : jusqu’à 78 % des messages perdus sur les nœuds n1, n3 et n5
  • NATS enquête actuellement sur ce problème

3.3 Suppression totale des données en cas de corruption de snapshot (#7556)

  • Si le fichier de snapshot sous data/jetstream/$SYS/_js_/ est corrompu, le nœud considère le flux comme orphaned et supprime toutes les données
  • La corruption d’une minorité de nœuds empêche d’atteindre le quorum et rend le flux permanemment indisponible
  • Exemple : corruption des nœuds n3 et n5 → élection de n3 comme leader et suppression complète de jepsen-stream
  • Jepsen souligne le risque qu’un nœud corrompu puisse être élu leader

3.4 Perte de données due au réglage fsync par défaut (#7564)

  • Par défaut, JetStream n’effectue un fsync que toutes les 2 minutes, alors que les messages sont acquittés immédiatement
    • En conséquence, les messages récemment acquittés peuvent ne pas avoir été persistés sur disque
  • Une panne d’alimentation ou un crash kernel peut entraîner la perte de plusieurs dizaines de secondes de messages acquittés
    • Exemple : 131 418 messages perdus sur 930 005
  • Des pannes de nœud enchaînées peuvent aussi provoquer la suppression complète du flux
  • Ce comportement est presque absent de la documentation
  • Jepsen recommande de modifier la valeur par défaut en fsync=always ou d’ajouter un avertissement explicite sur le risque de perte de données

3.5 Split-brain après un seul crash OS (#7567)

  • Une seule panne d’alimentation ou crash kernel d’un nœud peut provoquer des pertes de données et une incohérence de réplication
  • Dans une architecture leader-suiveur, si certains nœuds ont confirmé une écriture seulement en mémoire puis sont tombés en panne,
    la majorité des nœuds perd cette écriture et poursuit avec un nouvel état
  • Les tests ont observé un split-brain persistant après un seul événement de panne d’alimentation
    • Des pertes de messages acquittés sur des plages différentes ont été constatées selon le nœud
  • Jepsen cite des cas similaires chez Kafka pour souligner que ce risque existe aussi dans des systèmes basés sur Raft

4. Discussion et conclusion

  • Le problème de perte totale de données dans la version 2.10.22 est résolu en 2.10.23
  • En 2.12.1, des pertes de données et des split-brain subsistent en cas de corruption de fichiers et de crash OS
  • Une corruption des fichiers .blk ou snapshot peut provoquer des omissions de messages sur certains nœuds, ou la suppression complète du flux
  • L’intervalle de fsync par défaut, s’il reste long, crée un risque de perte de données acquittées en cas de pannes simultanées sur plusieurs nœuds
  • Jepsen propose fsync=always ou une mise en garde explicite dans la documentation
  • L’affirmation de JetStream selon laquelle il est « toujours disponible » est impossible selon CAP, ce qui implique une mise à jour de la documentation
  • Jepsen précise qu’il est possible de démontrer l’existence de bugs, mais pas d’impossibilité de sûreté

4.1 Rôle de LazyFS

  • Utilisation de LazyFS pour simuler la perte d’écritures non validées par fsync
  • Diverses erreurs de stockage, dont les écritures partiellement corrompues (torn write), sont reproduites lors d’un crash d’alimentation
  • Selon les travaux associés When Amnesia Strikes (VLDB 2024), des bugs similaires ont été signalés sur PostgreSQL, Redis, ZooKeeper, etc.

4.2 Pistes futures

  • Les pertes au niveau d’un seul consommateur, l’ordre des messages ainsi que les garanties Linearizable/Serializable n’ont pas encore été vérifiés
  • La garantie exactly-once est aussi identifiée comme sujet de recherche futur
  • Des erreurs de documentation et l’absence d’étapes de health check obligatoires lors de l’ajout/retrait de nœuds ont été trouvées (#7545)
  • Une procédure sûre de reconfiguration de cluster reste encore floue

Aucun commentaire pour le moment.

Aucun commentaire pour le moment.