Validation de TigerBeetle 0.16.11 par Jepsen
(jepsen.io)- La base de données OLTP en partie double TigerBeetle met en avant la sûreté et la rapidité, et Jepsen a vérifié la série 0.16.11 à 0.16.30 sur des clusters Debian de 3 à 6 nœuds avec injection de pannes
- Les tests combinent un ordre explicite des timestamps et un modèle de machine à états monothread fondé sur la documentation afin de vérifier à la fois la Strong Serializability et la sémantique des comptes, des transferts et des requêtes
- Les principaux bugs de sûreté concernaient des résultats manquants dans les requêtes à filtres multiples et une erreur de timestamp d’en-tête dans le client Java ; à partir de la 0.16.26, des résultats conformes aux affirmations de Strong Serializability ont été observés même sous plusieurs combinaisons de pannes
- Côté disponibilité, les tests ont révélé des réessais infinis côté client, des crashs de processus lors de l’eviction de session, une forte hausse de latence lors d’une panne d’un seul nœud, des panic serveur pendant des bit flips disque et des mises à niveau, ainsi que l’absence de chemin de récupération après perte de disque sur un nœud unique
- TigerBeetle 0.16.43 intègre la plupart des problèmes signalés, avec notamment une réduction de la latence en cas de panne d’un seul nœud et
tigerbeetle recover, et les opérateurs doivent consulter les notes de version lors du passage à 0.16.43 et lors de la transition vers 0.16.26 ou une version ultérieure
Conception de TigerBeetle et périmètre des tests
- TigerBeetle est une base de données OLTP en partie double qui ne stocke que des comptes (accounts) et des transferts (transfers), plutôt que des lignes, objets, graphes ou blobs arbitraires
- Elle promet une cohérence Strong Serializable fondée sur Viewstamped Replication (VR) et est conçue pour des modèles comme les transactions financières, l’inventaire, la billetterie ou la mesure de services publics
- Pour des charges à forte contention et haut débit, toutes les écritures passent par un seul cœur du nœud primary VR, avec une priorité donnée au scale-up plutôt qu’au scale-out
- Pour les performances, elle utilise le traitement par lots, la parallélisation des E/S, un schéma fixe, ainsi que des structures de données de taille fixe et alignées sur le cache
- Le modèle de panne traite explicitement la mémoire, les processus, les horloges, le stockage et le réseau
- Les processus peuvent se figer ou crasher
- Les horloges peuvent sauter en avant comme en arrière
- Les disques peuvent subir non seulement une panne totale, mais aussi des corruptions d’écriture partielles et une altération des données
- Le réseau peut provoquer latence, pertes, duplications, mauvais acheminements et corruption de messages
- TigerBeetle utilise des tests de simulation déterministes, et les tests VOPR simulent l’ensemble du cluster ainsi que les interfaces d’horloge, de disque et de réseau
Modèle de données et sémantique des requêtes
- Le modèle de données se compose de deux types d’enregistrements : accounts et transfers
- Un compte possède notamment un
id128 bits défini par l’utilisateur,ledger,flags,timestamp,code,user_data_32,user_data_64,user_data_128 - Un transfert est un enregistrement immuable comprenant
debit_account_id,credit_account_id,amount,ledger,flagset des champs définis par l’utilisateur
- Un compte possède notamment un
- Un transfert peut être immédiatement posté en une seule étape, ou prendre la forme d’un transfert en deux phases séparé en pending puis post/void
- Un pending transfer réserve de la capacité sur les comptes debit et credit
- Il est ensuite possible de poster ou d’annuler un montant inférieur ou égal au montant pending
- Le champ
timeoutpermet de contrôler l’expiration automatique
- Les comptes sont immuables à l’exception du drapeau
closedet des quatre champs de solde, et les transferts sont toujours immuables- Pour modifier ou annuler un transfert, il faut créer un nouveau transfert de compensation
- Chaque requête représente une opération logique d’un seul type et contient en général un lot pouvant aller jusqu’à 8190 événements
create_accounts,create_transferssont des requêtes d’écriturelookup_accounts,lookup_transfers,query_accounts,query_transfers,get_account_transfers,get_account_balancessont des requêtes de lecture
- Chaque requête constitue une transaction du point de vue de la base, mais certains événements au sein d’une requête validée peuvent échouer logiquement et renvoyer un code d’erreur
- Si une atomicité conditionnelle entre événements est nécessaire, on utilise chain afin que tous les événements d’une même chaîne réussissent ou échouent ensemble
Méthode de test Jepsen
- La suite de tests Jepsen combine tests basés sur des propriétés et injection de pannes à l’aide de la bibliothèque de test Jepsen
- Les versions testées vont de TigerBeetle 0.16.11 à 0.16.30, avec aussi plusieurs builds de développement
- Les clusters se composent de 3 à 6 nœuds Debian
- Les tests sont exécutés à la fois sur des conteneurs LXC et des VM EC2
- Le client officiel de TigerBeetle est un smart client connecté à tous les nœuds, ce qui peut masquer des erreurs de concurrence
- Jepsen teste aussi le comportement normal du smart client
- En parallèle, Jepsen utilise aussi une méthode limitant chaque client à un seul nœud
- Le validateur fonctionne en deux étapes
- Il lit les timestamps d’exécution des requêtes réussies, puis déduit les timestamps des écritures échouées ou en timeout à partir des effets observés ensuite
- Il exécute ensuite un modèle de machine à états TigerBeetle fondé sur la documentation dans l’ordre des timestamps déduits afin de vérifier les résultats et les codes d’erreur
- Le modèle de machine à états est écrit en plus de 1 600 lignes de Clojure et inclut des maps de comptes et de transferts, des index, des erreurs transitoires, des statistiques internes, l’écoulement du temps, etc.
- Il gère les ID dupliqués, les timestamps non monotones, les contraintes de solde, les drapeaux incompatibles, ainsi que l’exécution spéculative et le rollback des chain
- Il s’appuie sur la bibliothèque de structures de données persistantes haute performance Bifurcan
Injection de pannes et tests de corruption de fichiers
- Jepsen injecte
SIGKILL,SIGSTOPsur les processus, plusieurs formes de partition réseau, des modifications d’horloge allant de la milliseconde à plusieurs centaines de secondes, ainsi que des allers-retours rapides de l’horloge - Des mises à niveau de nœuds vers plusieurs versions sont aussi effectuées pendant les tests
- Un nouveau nemesis de corruption de fichiers a permis de créer divers incidents de stockage
- Des bit flips aléatoires simulent des corruptions de type interférence cosmique
- Le remplacement de chunks de fichier par d’autres chunks simule des misdirected writes
- La restauration ultérieure d’instantanés de chunks simule des lost writes
- Un nœud TigerBeetle possède un unique fichier de données, découpé en zones à offset prévisible
- Les tests ciblent certaines zones seulement, comme l’en-tête du WAL ou les copies redondantes de la zone superblock
- Ils incluent aussi des corruptions affectant plusieurs zones ou l’ensemble du fichier
- Une panne disque « helical » consiste à corrompre le fichier sur tous les nœuds, mais avec un chunk différent sur chaque nœud
- L’objectif est d’éviter qu’un même enregistrement soit irrémédiablement corrompu sur toutes les replicas, puisque la disposition des fichiers de replica récents de TigerBeetle est généralement identique bit à bit
- La tête du WAL constitue une exception, car sa position peut varier selon le nœud
Problèmes de sûreté identifiés
- Dans la version 0.16.13, les réponses de
query_accounts,query_transfersetget_account_transfersomettaient fréquemment une partie ou la totalité des résultats- Les résultats manquants se trouvaient toujours en fin de réponse, et la réponse correspondait à un préfixe du résultat correct
- Le problème n’apparaissait pas avec les requêtes à filtre unique, mais sur des combinaisons de filtres multiples comme
ledgeretcode - La cause était un bug de vérification des bornes dans le zig-zag merge join entre plusieurs index
- Le problème a été suivi dans #2544 et corrigé dans la version 0.16.17
- L’API d’en-tête du client Java, ajoutée en 0.16.13 pour prendre en charge les tests Jepsen, renvoyait des horodatages d’exécution erronés ou dupliqués
- La cause était l’objet de réponse singleton mutable
Batch.EMPTYdu client Java - Comme les réponses réussies étaient représentées par un batch vide, plusieurs réponses écrasaient l’en-tête du même objet
- Corrigé par #2495 et intégré à la version 0.16.14
- Cela n’affectait pas la cohérence réelle des données, uniquement les horodatages de requête de l’API d’en-tête du client Java
- La cause était l’objet de réponse singleton mutable
- Les résultats observés à partir de la version 0.16.26 sont cohérents avec l’affirmation de Strong Serializability de TigerBeetle
- Cette propriété est maintenue même avec des combinaisons de pauses de processus, crashs, partitions réseau, erreurs d’horloge, corruptions disque et mises à niveau
Problèmes liés au client et au traitement des requêtes
- La documentation de TigerBeetle explique que les requêtes n’expirent pas et que le client continue à réessayer jusqu’à recevoir une réponse
- Les méthodes asynchrones Java renvoient un
CompletableFutureet peuvent utiliser des API de timeout comme.get(timeout, timeUnit)ou.orTimeout(...) - Le
Taskdu client .NET propose aussi unWait()avec timeout
- Les méthodes asynchrones Java renvoient un
- Les tentatives infinies peuvent masquer à la fois les erreurs définies et les erreurs indéfinies
- Par exemple, si une connexion TCP échoue avec
ECONNREFUSED, il s’agit d’un échec défini : la requête d’origine ne peut pas être exécutée - Mais si le client ne le signale pas à l’appelant et continue simplement à réessayer en interne, cela devient, du point de vue de l’appelant, un échec indéfini comme un timeout ou une interruption
- Par exemple, si une connexion TCP échoue avec
- Ce sujet est discuté dans #206 et reste non résolu au moment du rapport
- Jepsen recommande de représenter les erreurs définies et indéfinies comme des éléments de premier ordre et de les renvoyer à l’appelant
- Les retries automatiques peuvent être conservés, mais devraient être configurables, avec des options pour le temps maximal d’établissement de connexion et d’attente de réponse
- Dans la version 0.16.11, le client Java provoquait parfois un segfault de toute la JVM lors du traitement des timeouts, lorsqu’un thread d’appel synchrone était interrompu ou quand le client était fermé après un appel asynchrone
- La cause était un champ non initialisé dans la structure de données de requête
- Si le client était fermé entre la création et l’envoi de la requête, l’adresse par défaut de Zig
0xaaa...était déréférencée - Corrigé par #2435 et intégré à la version 0.16.12
- Les clients officiels faisaient planter tout le processus lorsque le serveur signalait une éviction de session
- TigerBeetle limite par défaut le nombre de sessions concurrentes à 64
- Une éviction pouvait aussi se produire lorsqu’on utilisait une version de client plus récente que celle du serveur
- Depuis #2484, à partir de la version 0.16.13, une éviction renvoie une erreur à l’appelant au lieu de faire planter le processus
Forte hausse de latence en cas de panne d’un seul nœud
- Des hausses répétées de la latence client de 3 à 5 ordres de grandeur ont été observées lors de la panne d’un seul nœud
- Dans un cluster de 5 nœuds, tuer un seul nœud faisait passer la latence minimale de moins de 1 ms à 10 secondes
- Dans un test sur un cluster de 3 nœuds où un nœud était tué, une latence initialement comprise entre 1 et 50 ms montait jusqu’à environ 100 secondes par requête, et cela durait près de 1000 secondes jusqu’au redémarrage du nœud
- La cause est liée au mode de propagation des messages prepare dans TigerBeetle
- Dans VR traditionnel, le primary envoie les prepare à tous les secondary et reçoit directement leurs ACK
- TigerBeetle place les nœuds en anneau : le primary envoie le prepare au secondary suivant, puis chaque secondary le transmet au nœud suivant
- Cette approche réduit la bande passante requise par un nœud, mais si l’une des
fréplicas suivantes dans l’anneau tombe en panne, le commit peut être bloqué
- Ce problème est suivi dans #2739
- La version 0.16.30 l’atténue en envoyant la moitié des messages prepare dans le sens opposé de l’anneau
- Certains prepare peuvent ainsi contourner le nœud défaillant
- Dans les tests Jepsen, les latences de l’ordre de 100 secondes sont redescendues à une plage de 1 à 30 secondes
- La version 0.16.43 inclut des améliorations supplémentaires de performance
- Les nœuds répliquent désormais dans les deux sens de l’anneau
- La topologie en anneau devient dynamique, le cluster ajustant l’ordre des nœuds selon les conditions réseau et les pannes
Corruption disque et crash du serveur
- En version 0.16.20, une corruption d’un seul bit dans le superblock, le WAL ou une zone de grid pouvait provoquer un crash au démarrage
- Les logs affichaient
panic: reached unreachable codeavant l’arrêt - La cause était un bug dans la vérification du padding de secteur
- Les logs affichaient
- Les checksums de TigerBeetle couvrent les données des chunks, mais pas le padding
- Si un bit à 0 du padding passait à 1, le checksum restait valide
- Ensuite, une assertion vérifiant que le padding était toujours à 0 échouait, ce qui faisait planter le serveur
- Une corruption du padding n’affecte pas la sûreté et peut être corrigée en le remettant à 0 ou en restaurant depuis une autre réplique
- VOPR n’avait pas détecté ce bug, car il corrompait jusque-là des secteurs entiers
- La corruption d’un secteur entraînait un échec du checksum et déclenchait le chemin de réparation, sans jamais atteindre l’assertion sur le padding
- TigerBeetle a ajouté des erreurs sur un seul octet à VOPR dans #2681
- À partir de la version 0.16.26, les secteurs avec padding corrompu sont réparés au lieu de provoquer un crash
- Un bit flip dans le numéro de copie du superblock pouvait provoquer la même panic
- Les quatre copies du superblock ont chacune un numéro
copyde 2 octets différent, et le checksum ignore ce numéro - Si un numéro de copie corrompu était lu du disque en mémoire, une assertion sur la plage 0 à 3 échouait lors de l’écriture
- Ce problème a été résolu en 0.16.26 en réinitialisant le numéro de copie
- Les quatre copies du superblock ont chacune un numéro
Problèmes liés aux mises à niveau
- Lors d’une mise à niveau de 0.16.25 ou antérieur vers 0.16.26 ou ultérieur, le crash
panic: checkpoint divergeda été observé de manière répétée- La cause était une modification de la structure
CheckpointStatedans 0.16.26 - La nouvelle version incluait l’ensemble des released blocks, mais cette information pouvait être vide lors du transfert d’état compatible avec les versions précédentes
- Si le nœud redémarrait ensuite en 0.16.26, il pouvait se retrouver dans un état où il avait perdu les released blocks connus des autres replicas
- Une assertion détectait la divergence et provoquait un crash afin d’empêcher les clients d’observer des données incohérentes
- La cause était une modification de la structure
- Ce problème est documenté dans le changelog via #2745
- TigerBeetle n’a pas publié de version 0.16.26 corrigée
- Les opérateurs doivent arrêter les clients et attendre le rattrapage des replicas avant de passer à 0.16.26 ou à une version ultérieure
- Lors de plusieurs mises à niveau successives de 0.16.16 à 0.16.28 en environ 20 secondes, ou lorsqu’un nœud est mis en pause/crashe pendant une mise à niveau, un échec d’assertion
release_transitionse produit- Le nœud en cours d’exécution ouvre le nouveau binaire via
memfdpuis le remplace avecexec(), mais entre-temps le binaire sur disque peut être remplacé par une version plus récente - Le code échoue parce qu’il vérifie par assertion que la version sur disque, jusqu’au version header, est identique à la version actuellement exécutée
- #2758 transforme l’assertion en avertissement dans la version 0.16.29
- Le nœud en cours d’exécution ouvre le nouveau binaire via
- Lors d’une mise à niveau de 0.16.26 à 0.16.27, le type de message obsolète provoque
panic: switch on corrupt value- L’instruction
switchdu nouveau nœud ne contient pas de case pour l’ancien type de message, ce qui entraîne un crash - #2763 corrige cela dans 0.16.29 en réintroduisant le type de message obsolète dans les case pour l’ignorer
- L’instruction
Récupération après perte de disque sur un nœud unique
- TigerBeetle est robuste face à la corruption de fichiers, mais une panne de disque, un incendie, une erreur de volume EBS ou une erreur humaine peuvent faire disparaître totalement les fichiers de données d’un nœud ou les endommager de manière irréversible
- Au moment du rapport, la documentation n’expliquait pas comment remplacer un nœud défaillant, et il existait une procédure de récupération non documentée consistant à exécuter
tigerbeetle formatpour réinitialiser avec des fichiers de données vides, en espérant qu’une réparation suive - Jepsen a confirmé que le reformatage fonctionne le plus souvent, mais peut ne pas être sûr
- Si, dans un cluster de 3 nœuds, 2 nœuds possèdent une opération validée
opet que l’un d’eux est reformaté, une majorité de 2/3 n’ayant pas observéoppeut effectuer un changement de vue et l’opération peut être perdue - Lors des tests réels, une exécution a montré la perte de 5 transferts pourtant confirmés
- Des cas ont aussi été observés où un nœud formaté avec un binaire plus récent pendant une mise à niveau crashe au démarrage avant d’avoir terminé la transition de version du cluster
- Si, dans un cluster de 3 nœuds, 2 nœuds possèdent une opération validée
- Ce problème est suivi via #2767
- TigerBeetle 0.16.43 a ensuite introduit la commande
tigerbeetle recoverpour restaurer un nœud ayant subi une perte de données catastrophique
Conclusion et recommandations de Jepsen
- Deux problèmes de sûreté ont été découverts
- résultats manquants dans les requêtes multi-filtres avant 0.16.17
- horodatages erronés et dupliqués dans l’API de débogage du client Java utilisée pour les tests Jepsen
- Il y avait au total 7 problèmes de crash
- 2 côté client Java : accès à de la mémoire non initialisée, crash du processus lors d’une eviction
- 5 côté serveur : 2 panic liés à la corruption de disque, 3 panic liés aux mises à niveau
- #2745 a été documenté, et les autres crash ont été corrigés au plus tard en 0.16.29
- La version 0.16.43 corrige tous les problèmes du rapport sauf un
- le point non résolu est un problème où les requêtes client continuent à être retentées par conception
- Les recommandations aux utilisateurs sont claires
- mettre à niveau vers 0.16.43
- vérifier les release notes lors d’un passage vers 0.16.26 ou une version ultérieure
- simuler une panne sur un seul nœud dans l’environnement de test et mesurer comment l’application réagit à la hausse de latence
- L’architecture de TigerBeetle semble solide, et l’intégration de VR, du quorum flexible et d’une récupération consciente du protocole ne semble pas avoir compromis les invariants fondamentaux de la Strong Serializability
- Cependant, la validation de Jepsen repose sur une approche expérimentale : elle peut prouver la présence de bugs, mais non leur absence
1 commentaires
Commentaires sur Hacker News
À lire aussi : Fuzzer Blind Spots (Meet Jepsen!) – https://tigerbeetle.com/blog/2025-06-06-fuzzer-blind-spots-m...
Ce rapport est vraiment impressionnant. Chaque fois que je voyais les affirmations de TigerBeetle sur sa fiabilité et sa scalabilité, je me disais : « Très bien, attendons le rapport Jepsen »
Le rapport a révélé plusieurs problèmes, et on pourrait s’en inquiéter, mais le point positif est qu’ils ne se sont pas contentés de les corriger : ils ont aussi étendu leur suite de tests interne pour détecter à l’avenir des bugs similaires. Avec une telle approche d’ingénierie, dans dix ans, TigerBeetle pourrait devenir, dans le créneau des applications financières, la base de données par défaut au même titre que « il suffit d’utiliser Postgres »
Le travail d’aphyr est également excellent, et j’ai eu l’impression d’apprendre beaucoup en lisant le rapport
À part cela, si l’on exclut un petit bug de correction dans une fonctionnalité de test interne ajoutée uniquement au client Java pour aider l’audit Jepsen, Jepsen n’a trouvé qu’un seul bug de correction, qui n’affectait pas la durabilité. L’article correspondant est ici : https://tigerbeetle.com/blog/2025-06-06-fuzzer-blind-spots-m...
Pour être juste, TigerBeetle est conçu et testé pour tolérer davantage de pannes que Postgres. Il dispose d’un modèle explicite de pannes de stockage et s’appuie sur des recherches qui n’existaient pas lorsque Postgres est sorti en 1996. Le modèle de panne de TB est en outre validé par des tests de simulation déterministes, avec des techniques comme l’allocation mémoire statique conforme aux Power of Ten Rules de la NASA pour le code critique en matière de sûreté. La littérature décrit des scénarios connus dans lesquels Postgres perd des données, mais TigerBeetle peut les détecter et s’en remettre
Pour en savoir plus, voir la section helical fault injection du rapport de Kyle. La plupart des implémentations de Raft et Paxos ne sont pas conçues pour y résister, et il existe aussi une présentation QCon London : https://m.youtube.com/watch?v=_jfOk4L7CiY
Je suis vraiment content de voir que, d’après la vérification d’aphyr, TigerBeetle est à la hauteur de ses propres affirmations. C’est agréable de constater que choisir la bonne approche produit les bons résultats
Je me demande comment TigerBeetle s’utilise concrètement. Il doit y avoir beaucoup de systèmes externes et d’autres bases de données autour d’une installation TigerBeetle pour tout ce qui n’est pas Account ou Transfer ; je me demande quels sont les schémas typiques pour faire fonctionner ces systèmes moins fiables avec TigerBeetle, surtout lorsqu’un problème de cohérence apparaît entre les deux
Les informations utilisateur (nom, adresse, mot de passe, etc.) et les informations produit (description, prix, etc.) vont dans l’OLGP, comme dans un « classeur »
Et lors du Black Friday, toutes les transactions par lesquelles un utilisateur déplace un produit depuis un compte de stock vers un compte de panier, puis vers des comptes de paiement et d’expédition, vont dans l’OLTP, comme dans un « coffre-fort ». TigerBeetle permet de stocker jusqu’à trois identifiants de données utilisateur par compte ou par transfert, ce qui permet de relier les événements entre entités à la base de données OLGP qui décrit ces entités
Cette architecture [1] offre une séparation des préoccupations nette, permettant de faire évoluer et d’administrer indépendamment des charges de travail différentes. Pour une banque, il est plus logique de conserver l’argent liquide dans un coffre-fort, avec des caractéristiques différentes de performance, de conformité réglementaire et de conservation, plutôt que de le stocker dans le classeur contenant les dossiers clients
Ce schéma est pertinent parce que les utilisateurs changent de nom ou d’adresse e-mail (OLGP) bien moins souvent qu’ils n’effectuent des transactions (OLTP)
Pour préserver la cohérence, sur le chemin d’écriture, on traite TigerBeetle comme le plan de données OLTP et la « source de vérité ». Lorsqu’une transaction de type « déplacer vers le panier » ou « paiement » arrive, on écrit d’abord les dépendances de données nécessaires dans l’OLGP, puis, s’il y a des données blob associées, on les écrit aussi dans un service comme S3, et enfin on écrit dans TigerBeetle pour valider la transaction. Sur le chemin de lecture, on interroge d’abord la source de vérité afin de préserver une stricte sérialisabilité
[1] https://docs.tigerbeetle.com/coding/system-architecture/
Après avoir lu l’article de TigerBeetle sur les angles morts des fuzzers, ce rapport Jepsen est particulièrement intéressant
Le segfault côté JNI semble être quelque chose que Rust, ou un autre langage à sûreté mémoire, n’aurait pas empêché. Le fait qu’il y ait très peu de bugs de sûreté mémoire me semble prouver que l’approche de programmation Zig de TigerBeetle, TigerStyle si je me souviens bien, remplit plutôt bien le rôle prévu
Mais oui. Sans TigerStyle, les nasal demons nous seraient tombés dessus
J’apprécie ce rapport remarquablement détaillé. Le fait que Jepsen l’ait testé et validé constitue une énorme garantie pour TigerBeetle. Il n’a même pas encore atteint la v1.0, et j’ai hâte de voir les prochains jalons
Un coup de chapeau particulier aussi aux fondateurs qui partagent d’excellentes analyses dans ce fil
J’ai aussi hâte de découvrir les nouveautés qui seront bientôt partagées lors de la présentation SD25 à Amsterdam
J’aime bien, même si ce n’est qu’un détail, le titre de section « Panic! At the Disk 0 »
Le fait que le système distribué testé doive rapporter le moment et l’ordre réels des événements, afin de pouvoir le vérifier précisément par rapport au modèle externe du système au lieu d’utiliser l’heure de l’horloge murale, paraît évident avec le recul, mais reste intéressant
C’est un méta-motif intéressant : lorsqu’on accomplit quelque chose de plus difficile, le système devient en fait plus simple
Autre exemple : en supposant que les disques peuvent tomber en panne et en incluant un protocole de récupération, on obtient presque « gratuitement » la synchronisation de l’état des réplicas en retard. C’est exactement le même problème que celui d’un disque entier corrompu
Dans l’article, le lien vers le papier « Viewstamped Replication » est malheureusement cassé. https://pmg.csail.mit.edu/papers/vr-revisited.pdf refuse la connexion
Il faut probablement utiliser le schéma http plutôt que https, comme dans http://pmg.csail.mit.edu/papers/vr-revisited.pdf
Voilà de quoi lire vendredi soir
Le papier VSR de 2012 est l’un de mes préférés, et « Protocol-Aware Recovery for Consensus-Based Storage » est également très solide
Bonne lecture
Je pose la question uniquement pour apprendre, et j’espère qu’elle ne sera pas mal interprétée. Je débute encore dans les systèmes distribués et je suis fasciné par les tests par simulation déterministe
Après avoir parcouru rapidement le rapport Jepsen sur TigerBeetle, les billets de blog associés et le code d’intégration d’Antithesis dans les workflows GitHub, j’ai voulu mieux comprendre la couverture de test
La question centrale est de savoir si l’intégration Antithesis aurait elle aussi pu trouver ces bugs découverts par la suite de tests Jepsen
Ma question repose sur quelques hypothèses qui peuvent être fausses. Je pensais que TigerBeetle était déjà testé de manière exhaustive par sa suite de tests interne et par le produit Antithesis, et j’avais compris que la suite de tests Antithesis était plus puissante que Jepsen ; j’ai donc été surpris que Jepsen découvre des problèmes qu’Antithesis n’avait pas trouvés
J’aimerais savoir si ma compréhension est erronée. Par exemple, je voudrais comprendre si 1) la suite de tests Antithesis ne pouvait pas détecter cette catégorie précise de bugs, 2) cette partie du système n’était pas encore couverte par les tests Antithesis, ou 3) je compare des choses incomparables parce que je comprends mal les forces et objectifs respectifs des suites de tests Jepsen et Antithesis
Le générateur de tests de Jepsen a presque certainement lui aussi des angles morts. C’est pourquoi concevoir des générateurs différents est utile
Antithesis traite principalement le premier problème, en fournissant un environnement de simulation déterministe à base de machines virtuelles. Jepsen aborde le même problème avec des machines réelles, mais en injectant des pannes au niveau du système d’exploitation, tandis que le VOPR maison de TigerBeetle est conçu avec la base de données de façon à pouvoir exécuter tout le cluster dans un seul thread. Ces trois approches sont complémentaires et chacune excelle dans des domaines différents
Pour ce bug, les éléments décisifs relevaient des points 2 et 3 : écrire un validateur de charge et un auditeur capables de déclencher réellement le bug. Ici, les 1 600 lignes de code Clojure spécifiques à TigerBeetle écrites par aphyr ont déclenché et détecté le bug, puis les tests équivalents côté TigerBeetle ont été patchés pour le déclencher eux aussi. En réalité, ce qui était buggé ici, ce n’était pas tant la base de données que VOPR. Qu’une base de données ait des bugs est normal, et on ne peut pas les éviter par la seule volonté. Il faut donc une stratégie de test capable de déclencher la plupart des bugs, et les bugs qui passent entre les mailles signalent un défaut du générateur de charge
Antithesis est aussi utilisé, mais comme deuxième couche de tests par simulation déterministe
Pour savoir pourquoi le bug du moteur de requêtes est passé entre les mailles, voir ici : https://tigerbeetle.com/blog/2025-06-06-fuzzer-blind-spots-m...
Je me demande si de grandes banques ou des places boursières utilisent TigerBeetle
Côté entreprises, TigerBeetle est déjà utilisé en production par des clients qui traitent plus de 100 millions de transactions par mois, a récemment signé son premier contrat avec une licorne fintech européenne valorisée 2 milliards de dollars, et plusieurs dossiers devraient bientôt être finalisés aux États-Unis. Avec le mouvement mondial vers le traitement des transactions en temps réel [2], beaucoup d’entreprises s’intéressent à une migration vers TigerBeetle pour obtenir de meilleures performances.
Pour répondre à la question, certains fondateurs de Clear Street, une assez grande société de courtage de Wall Street, ont investi dans TigerBeetle [3].
[1] https://mojaloop.io/how-mojaloop-enables-rndps-2-0-ekash/
[2] https://tigerbeetle.com/blog/2024-07-23-rediscovering-transa...
[3] https://tigerbeetle.com/company