Jepsen-Überprüfung von TigerBeetle 0.16.11
(jepsen.io)- Die OLTP-Datenbank TigerBeetle für doppelte Buchführung stellt Sicherheit und Geschwindigkeit in den Vordergrund; Jepsen überprüfte die 0.16.11- bis 0.16.30-Reihe in Debian-Clustern mit 3 bis 6 Maschinen unter Fault Injection
- Die Tests kombinierten eine explizite Zeitstempel-Reihenfolge mit einem dokumentationsbasierten, single-threaded State-Machine-Modell und prüften Strong Serializability sowie die Semantik von Konten, Transfers und Queries gemeinsam
- Die wichtigsten Sicherheits-Bugs waren fehlende Ergebnisse bei Multi-Filter-Queries und ein fehlerhafter Header-Zeitstempel im Java-Client; ab 0.16.26 wurden auch unter mehreren Fehlerkombinationen Ergebnisse beobachtet, die mit dem Anspruch auf Strong Serializability übereinstimmen
- Bei der Verfügbarkeit zeigten sich endlose Client-Retries, Prozess-Crashes bei Session Eviction, stark steigende Latenzen bei Ausfall eines einzelnen Knotens, Server-Panics bei Disk-Bitflips und während Upgrades sowie ein fehlender Recovery-Pfad nach Disk-Verlust auf einem einzelnen Knoten
- TigerBeetle 0.16.43 berücksichtigt die meisten gemeldeten Issues, enthält eine Entschärfung der Latenzen bei Einzelknotenausfällen sowie
tigerbeetle recover; Betreiber sollten auf 0.16.43 upgraden und beim Umstieg auf 0.16.26 oder neuer die Release Notes prüfen
Design und Testumfang von TigerBeetle
- TigerBeetle ist eine OLTP-Datenbank für doppelte Buchführung und speichert statt beliebiger Zeilen, Objekte, Graphen oder Blobs nur Konten (accounts) und Transfers (transfers)
- Auf Basis von Viewstamped Replication (VR) verspricht TigerBeetle Strong-Serializable-Konsistenz und ist für Modelle wie Finanztransaktionen, Bestände, Ticketing und Verbrauchsmessung bei Versorgern ausgelegt
- Für Workloads mit hoher Contention und hohem Durchsatz laufen alle Writes über einen einzelnen Core des primären VR-Knotens; der Fokus liegt auf Scale-up statt Scale-out
- Für Performance nutzt TigerBeetle Batch-Verarbeitung, I/O-Parallelisierung, ein festes Schema sowie Datenstrukturen mit fester Größe und Cache-Ausrichtung
- Das Fehlermodell behandelt Speicher, Prozesse, Uhren, Storage und Netzwerk explizit
- Prozesse können anhalten oder crashen
- Uhren können vor- und zurückspringen
- Disks können nicht nur komplett ausfallen, sondern auch teilweise Schreibkorruption und Datenverunreinigung erleiden
- Das Netzwerk kann Latenz, Drops, Duplikate, Fehlzustellungen und Nachrichtenkorruption verursachen
- TigerBeetle verwendet deterministische Simulationstests; die VOPR-Tests simulieren den gesamten Cluster sowie Uhr-, Disk- und Netzwerk-Interfaces
Datenmodell und Request-Semantik
- Das Datenmodell besteht aus zwei Arten von Records: accounts und transfers
- Ein Konto hat unter anderem eine benutzerdefinierte 128-Bit-
id,ledger,flags,timestamp,code,user_data_32,user_data_64unduser_data_128 - Ein Transfer ist ein unveränderlicher Record mit
debit_account_id,credit_account_id,amount,ledger,flagsund benutzerdefinierten Feldern
- Ein Konto hat unter anderem eine benutzerdefinierte 128-Bit-
- Transfers können in einem einzelnen Schritt sofort gepostet werden; außerdem sind zweistufige Transfers mit pending sowie post/void möglich
- Ein pending transfer reserviert Kapazität auf dem Debit- und dem Credit-Konto
- Anschließend kann ein Betrag bis zur pending amount gepostet oder voided werden
- Das Feld
timeoutsteuert die automatische Ablaufzeit
- Konten sind unveränderlich, abgesehen vom
closed-Flag und vier Saldo-Feldern; Transfers sind immer unveränderlich- Um einen Transfer zu ändern oder rückgängig zu machen, muss ein neuer Ausgleichstransfer erstellt werden
- Ein Request repräsentiert eine einzelne Art logischer Operation und enthält üblicherweise Batches von bis zu 8190 Events
create_accountsundcreate_transferssind Write-Requestslookup_accounts,lookup_transfers,query_accounts,query_transfers,get_account_transfersundget_account_balancessind Read-Requests
- Aus Sicht der Datenbank ist jeder Request eine Transaktion, doch einzelne Events innerhalb eines committeten Requests können logisch fehlschlagen und einen Fehlercode zurückgeben
- Wenn bedingte Atomarität zwischen Events erforderlich ist, lässt sich chain verwenden, damit alle Events innerhalb derselben chain entweder erfolgreich sind oder fehlschlagen
Jepsens Testansatz
- Die Jepsen-Test-Suite nutzt die Jepsen testing library und kombiniert property-based Testing mit Fault Injection
- Testgegenstand waren TigerBeetle 0.16.11 bis 0.16.30, einschließlich mehrerer Entwicklungs-Builds
- Die Cluster bestanden aus 3 bis 6 Debian-Knoten
- Die Tests liefen sowohl in LXC-Containern als auch auf EC2-VMs
- Der offizielle TigerBeetle-Client ist ein Smart Client, der sich mit allen Knoten verbindet und dadurch Concurrency-Fehler verbergen kann
- Jepsen testete auch das normale Smart-Client-Verhalten
- Gleichzeitig wurde ein Ansatz genutzt, bei dem jeder Client auf einen einzelnen Knoten beschränkt wurde
- Der Verifier arbeitet in zwei Schritten
- Er liest die Ausführungszeitstempel erfolgreicher Requests und leitet für fehlgeschlagene oder per Timeout abgebrochene Writes die Zeitstempel aus später beobachteten Effekten ab
- In der Reihenfolge der abgeleiteten Zeitstempel führt er ein dokumentationsbasiertes TigerBeetle-State-Machine-Modell aus und verifiziert Ergebnisse und Fehlercodes
- Das State-Machine-Modell umfasst über 1.600 Zeilen Clojure und enthält Konto- und Transfer-Maps, Indizes, transiente Fehler, interne Statistiken und den Uhrverlauf
- Es behandelt doppelte IDs, nicht-monotone Zeitstempel, Saldo-Constraints, inkompatible Flags sowie speculative execution und Rollback von chain
- Es nutzt die performante Bibliothek für persistente Datenstrukturen Bifurcan
Fault Injection und Tests auf Dateikorruption
- Jepsen injizierte Prozess-
SIGKILL,SIGSTOP, verschiedene Formen von Netzwerkpartitionen, Uhränderungen von Millisekunden bis zu Hunderten Sekunden sowie schnelle Hin-und-zurück-Änderungen der Uhr - Während der Tests wurden auch Knoten-Upgrades über mehrere Versionen hinweg durchgeführt
- Ein neuer Nemesis für Dateikorruption erzeugte verschiedene Storage-Fehler
- Zufällige Bitflips simulierten Schäden wie durch kosmische Strahlung
- Das Ersetzen von Datei-Chunks durch andere Chunks simulierte misdirected writes
- Das spätere Wiederherstellen von Snapshots von Datei-Chunks simulierte lost writes
- TigerBeetle-Knoten haben eine einzelne Datendatei, die in Zonen mit vorhersagbaren Offsets unterteilt ist
- Tests beschädigten gezielt nur bestimmte Zonen, etwa den WAL-Header oder redundante Kopien in der Superblock-Zone
- Enthalten waren auch Tests, die mehrere Zonen oder die gesamte Datei beschädigten
- Ein „helical“ Disk Fault beschädigt die Dateien aller Knoten, aber auf jedem Knoten jeweils einen anderen Chunk
- Ziel ist, eine Situation zu vermeiden, in der ein einzelner Record auf allen Replicas irreparabel beschädigt wird, da die aktuellen Replica-Datei-Layouts von TigerBeetle in der Regel bitgenau identisch sind
- Eine Ausnahme ist der Head des WAL, dessen Position je nach Knoten unterschiedlich sein kann
Entdeckte Sicherheitsprobleme
- In 0.16.13 trat häufig ein Problem auf, bei dem Antworten von
query_accounts,query_transfersundget_account_transferseinige oder alle Ergebnisse ausließen- Die fehlenden Ergebnisse befanden sich immer am Ende der Antwort, und die Antwort war ein Präfix der korrekten Ergebnisse
- Bei Abfragen mit einem einzelnen Filter trat es nicht auf, sondern bei Kombinationen mehrerer Filter wie
ledgerundcode - Ursache war ein Bounds-Check-Bug im Zig-Zag Merge Join zwischen mehreren Indizes
- Wurde in #2544 nachverfolgt und in 0.16.17 behoben
- Die Java-Client-Header-API, die in 0.16.13 zur Unterstützung von Jepsen-Tests hinzugefügt wurde, gab falsche oder doppelte Ausführungszeitstempel zurück
- Ursache war das veränderbare Singleton-Antwortobjekt
Batch.EMPTYim Java-Client - Da erfolgreiche Antworten als leerer Batch dargestellt wurden, überschrieben mehrere Antworten den Header desselben Objekts
- Wurde mit #2495 behoben und in 0.16.14 übernommen
- Beeinträchtigte nicht die tatsächliche Datenkonsistenz, sondern nur die Anfragezeitstempel der Java-Client-Header-API
- Ursache war das veränderbare Singleton-Antwortobjekt
- Die ab 0.16.26 beobachteten Ergebnisse stimmen mit TigerBeetles Anspruch auf Strong Serializability überein
- Diese Eigenschaft blieb auch bei Kombinationen aus Prozess-Pause, Crash, Netzwerk-Partition, Clock Error, Disk Corruption und Upgrade erhalten
Probleme bei Client und Anfrageverarbeitung
- Die TigerBeetle-Dokumentation beschreibt, dass Anfragen nicht timeouten und der Client so lange retryt, bis er eine Antwort erhält
- Die asynchronen Java-Methoden geben ein
CompletableFuturezurück und können Timeout-APIs wie.get(timeout, timeUnit)oder.orTimeout(...)verwenden - Auch
Taskim .NET-Client bietet ein timeout-basiertesWait()
- Die asynchronen Java-Methoden geben ein
- Unendliches Retry kann sowohl definite errors als auch indefinite errors verbergen
- Wenn beispielsweise eine TCP-Verbindung mit
ECONNREFUSEDfehlschlägt, ist das ein definite failure, weil die ursprüngliche Anfrage nicht ausgeführt worden sein kann - Wenn der Client dies dem Aufrufer jedoch nicht meldet und intern nur weiter retryt, wird daraus aus Sicht des Aufrufers ein indefinite failure wie ein Timeout oder Abbruch
- Wenn beispielsweise eine TCP-Verbindung mit
- Dieses Problem wird in #206 diskutiert und ist zum Zeitpunkt des Berichts ungelöst
- Jepsen empfiehlt, definite errors und indefinite errors als erstklassige Konzepte darzustellen und an den Aufrufer zurückzugeben
- Automatisches Retry kann beibehalten werden, sollte aber konfigurierbar sein; außerdem werden Optionen für die maximale Dauer von Verbindungsaufbau und Warten auf eine Antwort empfohlen
- Der Java-Client 0.16.11 hatte bei der Timeout-Behandlung ein Problem, bei dem die gesamte JVM segfaultete, wenn der synchrone Aufruf-Thread interruptet oder der Client nach einem asynchronen Aufruf geschlossen wurde
- Ursache war ein nicht gesetztes Feld in der request data structure
- Wurde der Client zwischen Erzeugen und Abschicken der Anfrage geschlossen, dereferenzierte er die Zig-Standardadresse
0xaaa... - Wurde mit #2435 behoben und in 0.16.12 übernommen
- Die offiziellen Clients ließen den gesamten Prozess crashen, wenn der Server eine Session Eviction meldete
- TigerBeetle begrenzt concurrent sessions standardmäßig auf 64
- Eviction tritt auch auf, wenn eine neuere Client-Version als die Server-Version verwendet wird
- Seit #2484 gibt der Client ab 0.16.13 bei Eviction einen Fehler an den Aufrufer zurück, statt den Prozess crashen zu lassen
Starker Latenzanstieg bei Ausfall eines einzelnen Knotens
- Bei Ausfall eines einzelnen Knotens kam es wiederholt zu Fällen, in denen die Client-Latenz um 3 bis 5 Größenordnungen anstieg
- In einem 5-Knoten-Cluster stieg die minimale Latenz beim Beenden eines einzelnen Knotens von unter 1 ms auf 10 Sekunden
- In einem Test mit einem 3-Knoten-Cluster, bei dem ein Knoten beendet wurde, stieg die Latenz von 1–50 ms auf etwa 100 Sekunden pro Anfrage und hielt bis zum Neustart des Knotens fast 1000 Sekunden an
- Die Ursache hängt mit TigerBeetles Art der Prepare-Weiterleitung zusammen
- Klassisches VR lässt den Primary Prepare-Nachrichten an alle Secondaries senden und Acks direkt empfangen
- TigerBeetle ordnet Knoten in einem Ring an: Sendet der Primary ein Prepare an den nächsten Secondary, leitet jeder Secondary es an den nächsten Knoten weiter
- Dieses Verfahren reduziert die Bandwidth-Anforderungen an einen einzelnen Knoten, kann aber Commits blockieren, wenn einer der nächsten
fReplicas im Ring ausfällt
- Dieses Problem wird in #2739 nachverfolgt
- 0.16.30 entschärfte es, indem die Hälfte der Prepare-Nachrichten in die Gegenrichtung des Rings gesendet wird
- Einige Prepares können den ausgefallenen Knoten umgehen
- In Jepsen-Tests sank die Latenz im Bereich von 100 Sekunden auf etwa 1–30 Sekunden
- 0.16.43 enthält weitere Performance-Verbesserungen
- Knoten replizieren in beide Richtungen des Rings
- Die Ring-Topology ändert sich dynamisch, und der Cluster passt die Knotenreihenfolge an Netzwerkbedingungen und Ausfälle an
Disk Corruption und Server-Crashes
- In 0.16.20 gab es Fälle, in denen eine Single-Bit-Corruption im Superblock, WAL oder in einer Grid Zone beim Start einen Crash auslöste
- Das Log gab
panic: reached unreachable codeaus und beendete sich - Ursache war ein Bug in der Prüfung des Sector Padding
- Das Log gab
- TigerBeetles Checksum deckt die Daten eines Chunks ab, schließt Padding aber aus
- Wenn ein 0-Bit im Padding zu 1 wird, besteht die Checksum-Prüfung trotzdem
- Anschließend schlägt eine Assertion fehl, die prüft, ob das Padding weiterhin 0 ist, und der Server crasht
- Padding-Corruption beeinträchtigt die Safety nicht und kann wieder auf 0 gesetzt oder von einer anderen Replica wiederhergestellt werden
- VOPR fand diesen Bug nicht, weil es zuvor ganze Sectors beschädigte
- Sector-Corruption führte zu Checksum-Fehlern und dem Repair-Pfad, sodass die Padding-Assertion nicht erreicht wurde
- TigerBeetle fügte VOPR in #2681 Single-Byte-Errors hinzu
- Seit 0.16.26 werden Sectors mit Padding-Corruption repariert, statt einen Crash auszulösen
- Auch ein Bitflip in der Superblock-Copy-Number konnte dieselbe Panic auslösen
- Die vier Kopien des Superblocks haben jeweils unterschiedliche 2-Byte-
copy-Nummern, und die Checksum überspringt diese Nummer - Nachdem eine auf Disk beschädigte Copy Number in den Speicher gelesen wurde, ließ sie beim Schreiben die Assertion für den Bereich 0–3 fehlschlagen
- In 0.16.26 wurde dies durch Zurücksetzen der Copy Number gelöst
- Die vier Kopien des Superblocks haben jeweils unterschiedliche 2-Byte-
Probleme im Zusammenhang mit Upgrades
- Beim Upgrade von 0.16.25 oder älter auf 0.16.26 oder neuer wurde wiederholt ein Crash mit
panic: checkpoint divergedbeobachtet- Ursache war eine Änderung an der Struktur
CheckpointStatein 0.16.26 - Die neue Version enthielt die Menge der released blocks, doch bei der Übertragung eines mit älteren Versionen kompatiblen Zustands konnte diese Information leer sein
- Wenn ein Knoten anschließend mit 0.16.26 neu gestartet wurde, konnte er sich in einem Zustand befinden, in dem er die released blocks verloren hatte, die andere Replicas kannten
- Eine Assertion erkannte die Divergenz und löste einen Crash aus, wodurch verhindert wurde, dass Clients inkonsistente Daten beobachten
- Ursache war eine Änderung an der Struktur
- Dieses Problem wurde mit #2745 im Changelog dokumentiert
- TigerBeetle veröffentlichte keine gepatchte 0.16.26
- Betreiber sollten Clients anhalten und auf das Catch-up der Replicas warten, bevor sie auf 0.16.26 oder neuer upgraden
- Wenn von 0.16.16 auf 0.16.28 mehrere Upgrades innerhalb von etwa 20 Sekunden nacheinander ausgeführt wurden oder während eines Upgrades ein Knoten pausiert bzw. abstürzte, trat ein
release_transition-Assertion-Failure auf- Laufende Knoten öffnen das neue Binary per
memfdund ersetzen sich perexec(), doch in der Zwischenzeit kann das Binary auf der Festplatte durch eine noch neuere Version ersetzt werden - Der Code scheiterte, weil er per Assertion annahm, dass auch der Version-Header auf der Festplatte der aktuell ausgeführten Version entspricht
- Mit #2758 wurde die Assertion in 0.16.29 in eine Warnung geändert
- Laufende Knoten öffnen das neue Binary per
- Beim Upgrade von 0.16.26 auf 0.16.27 trat wegen eines deprecated message type ein
panic: switch on corrupt valueauf- Im
switch-Statement des neuen Knotens fehlte ein Case für den alten Nachrichtentyp, wodurch er abstürzte - Mit #2763 wurde der deprecated message type in 0.16.29 wieder als Case aufgenommen und so geändert, dass er ignoriert wird
- Im
Wiederherstellung nach Festplattenverlust eines einzelnen Knotens
- TigerBeetle ist robust gegen Dateibeschädigungen, doch durch Festplattenausfall, Feuer, EBS-Volume-Fehler, Bedienfehler usw. kann die gesamte Datendatei eines Knotens verschwinden oder irreparabel beschädigt werden
- In der Dokumentation zum Zeitpunkt des Berichts gab es keine Methode zum Ersetzen eines ausgefallenen Knotens; als undokumentiertes Recovery-Verfahren existierte der Ansatz, mit
tigerbeetle formateine leere Datendatei zu initialisieren und anschließend auf eine Reparatur zu hoffen - Jepsen stellte fest, dass Reformatierung meistens funktioniert, aber unsicher sein kann
- Wenn in 2 von 3 Knoten eine committed Operation
opvorhanden ist und einer davon neu formatiert wird, kann eine 2/3-Mehrheit, dieopnicht beobachtet hat, einen View Change durchführen, wodurch die Operation verloren gehen kann - In einem realen Testlauf gingen 5 bestätigte Transfers verloren
- Außerdem gab es Fälle, in denen ein Knoten, der während eines Upgrades mit einem neueren Binary formatiert wurde, beim Start abstürzte, bevor die Cluster-Version-Transition abgeschlossen war
- Wenn in 2 von 3 Knoten eine committed Operation
- Dieses Problem wird unter #2767 verfolgt
- Später enthielt TigerBeetle 0.16.43 den Befehl
tigerbeetle recoverzur Wiederherstellung von Knoten nach catastrophic data loss
Jepsens Fazit und Empfehlungen
- Es wurden zwei Sicherheitsprobleme gefunden
- Fehlende Ergebnisse bei Multi-Filter-Abfragen vor 0.16.17
- Falsche bzw. doppelte Timestamps in der Debugging-API des Java-Clients für Jepsen-Tests
- Insgesamt gab es 7 Crash-Probleme
- 2 im Java-Client: uninitialized memory access, Prozess-Crash bei Eviction
- 5 im Server: 2 Panics im Zusammenhang mit Festplattenbeschädigung, 3 Panics im Zusammenhang mit Upgrades
- #2745 wurde dokumentiert, die übrigen Crashs wurden bis 0.16.29 behoben
- 0.16.43 behebt bis auf eines alle im Bericht genannten Issues
- Der unresolved Punkt ist das Problem, dass Client Requests designbedingt fortlaufend erneut versucht werden
- Die Empfehlung für Nutzer ist klar
- Auf 0.16.43 upgraden
- Beim Wechsel auf 0.16.26 oder eine spätere Version die Release Notes prüfen
- In der Testumgebung den Ausfall eines einzelnen Knotens simulieren und messen, wie die Anwendung auf erhöhte Latenz reagiert
- Die Architektur von TigerBeetle wirkt solide; es wurde beobachtet, dass die Integration von VR, flexible quorum und protocol-aware recovery die zentralen Invarianten von Strong Serializability nicht verletzt
- Allerdings ist Jepsen-Verifikation ein experimenteller Ansatz: Sie kann die Existenz von Bugs nachweisen, nicht aber deren Abwesenheit
1 Kommentare
Hacker-News-Kommentare
Ebenfalls lesenswert: Fuzzer Blind Spots (Meet Jepsen!) – https://tigerbeetle.com/blog/2025-06-06-fuzzer-blind-spots-m...
Dieser Bericht ist wirklich beeindruckend. Immer wenn ich TigerBeetles Behauptungen zu Zuverlässigkeit und Skalierbarkeit gesehen habe, dachte ich: „Okay, warten wir mal auf den Jepsen-Bericht.“
Im Bericht wurden mehrere Probleme gefunden, und man könnte sich darüber Sorgen machen. Positiv ist aber, dass sie es nicht einfach beim Fixen belassen haben, sondern ihre internen Testsuites erweitert haben, um ähnliche Bugs künftig zu finden. Mit so einem Engineering-Ansatz könnte TigerBeetle in zehn Jahren in der Nische für Finanzanwendungen die Standarddatenbank auf dem Niveau von „nimm einfach Postgres“ werden.
Auch aphyrs Arbeit war großartig; beim Lesen des Berichts hatte ich das Gefühl, viel gelernt zu haben.
Abgesehen davon fand Jepsen – mit Ausnahme eines kleinen Korrektheitsfehlers in einer internen Testfunktion, die nur in den Java-Client eingebaut wurde, um das Jepsen-Audit zu unterstützen – nur einen einzigen Korrektheitsbug, der die Dauerhaftigkeit nicht beeinträchtigte. Der zugehörige Artikel ist hier: https://tigerbeetle.com/blog/2025-06-06-fuzzer-blind-spots-m...
Fairerweise ist TigerBeetle so entworfen und getestet, dass es mehr Ausfälle verkraftet als Postgres. Das liegt daran, dass es ein explizites Storage-Failure-Modell hat und Forschung nutzt, die es 1996, als Postgres erschien, noch nicht gab. Das Fehlermodell von TB wird zusätzlich durch deterministisches Simulation Testing validiert; außerdem kommen Techniken wie statische Speicherallokation nach NASAs Power of Ten Rules für Safety-Critical Code zum Einsatz. In der Literatur sind Szenarien bekannt, in denen Postgres Daten verlieren kann; TigerBeetle kann diese erkennen und wiederherstellen.
Wer mehr wissen will, sollte im Bericht von Kyle den Abschnitt zu helical fault injection lesen. Die meisten Raft- und Paxos-Implementierungen sind nicht dafür ausgelegt, das auszuhalten; dazu gibt es auch einen QCon-London-Vortrag: https://m.youtube.com/watch?v=_jfOk4L7CiY
Es freut mich wirklich zu sehen, dass TigerBeetle nach der Prüfung durch aphyr seinen eigenen Ansprüchen gerecht wird. Es ist schön zu sehen, dass der richtige Ansatz zu den richtigen Ergebnissen führt.
Ich frage mich, wie TigerBeetle in der Praxis eingesetzt wird. Für alles, was nicht Account oder Transfer ist, wird es rund um eine TigerBeetle-Installation vermutlich viele externe Systeme und andere Datenbanken geben. Mich interessiert, welche typischen Muster es gibt, mit denen diese weniger verlässlichen Systeme mit TigerBeetle synchron gehalten werden, insbesondere wie man sich erholt, wenn zwischen beiden Konsistenzprobleme auftreten.
Benutzerinformationen (Name, Adresse, Passwort usw.) und Produktinformationen (Beschreibung, Preis usw.) legt man als „Aktenschrank“ in OLGP ab.
Und alle Transaktionen am Black Friday, bei denen Nutzer Produkte vom Lagerkonto in das Warenkorb-Konto und weiter in Zahlungs- und Versandkonten verschieben, legt man als „Tresor“ in OLTP ab. TigerBeetle erlaubt es, pro Account oder Transfer bis zu drei benutzerdefinierte Daten-IDs zu speichern, sodass man Events zwischen Entitäten mit der OLGP-Datenbank verknüpfen kann, die diese Entitäten beschreibt.
Diese Architektur [1] bietet eine saubere Trennung der Zuständigkeiten, sodass unterschiedliche Workloads unabhängig skaliert und verwaltet werden können. Bei einer Bank ist es sinnvoller, Bargeld mit anderen Performance-, Compliance- und Aufbewahrungseigenschaften im Tresor aufzubewahren, statt es im Aktenschrank mit den Kundendaten zu lagern.
Dieses Muster passt, weil Nutzer ihren Namen oder ihre E-Mail-Adresse (OLGP) deutlich seltener ändern, als sie Transaktionen durchführen (OLTP).
Um Konsistenz zu wahren, behandelt man TigerBeetle im Schreibpfad als OLTP-Data-Plane und als „Source of Record“. Wenn eine Transaktion wie „in den Warenkorb verschieben“ oder „bezahlen“ hereinkommt, schreibt man zuerst die erforderlichen Datenabhängigkeiten nach OLGP, außerdem relevante Blob-Daten gegebenenfalls an einen Ort wie S3, und schreibt zuletzt nach TigerBeetle, um die Transaktion zu committen. Im Lesepfad fragt man zuerst die Source of Record ab, um strikte Serialisierbarkeit zu erhalten.
[1] https://docs.tigerbeetle.com/coding/system-architecture/
Nach der Lektüre von TigerBeetles Artikel über Fuzzer-Blind-Spots ist das ein besonders interessanter Jepsen-Bericht.
Der Segfault auf der JNI-Seite sieht so aus, als hätte ihn auch Rust oder eine andere speichersichere Sprache nicht verhindert. Dass es kaum Memory-Safety-Bugs gibt, wirkt wie ein ziemlich guter Beleg dafür, dass TigerBeetles Zig-Programmieransatz – wenn ich mich richtig erinnere, TigerStyle – die Rolle erfüllt, für die er gedacht ist.
Aber ja, das stimmt. Ohne TigerStyle wären sie den nasal demons zum Opfer gefallen.
Mir gefällt der hervorragend detaillierte Bericht. Dass Jepsen getestet und unterschrieben hat, ist eine enorme Gewährleistung für TigerBeetle. Es hat noch nicht einmal v1.0 erreicht, und ich freue mich schon auf die kommenden neuen Meilensteine.
Besonderer Applaus auch für die Gründer, die in diesem Thread gute Einblicke teilen.
Ich freue mich auch darauf, dass er bald beim SD25-Vortrag in Amsterdam Neues teilen wird.
Der Abschnittstitel „Panic! At the Disk 0“ gefällt mir zumindest ein kleines bisschen.
Im Nachhinein ist es offensichtlich, aber interessant, dass das getestete verteilte System die tatsächliche Zeit und Reihenfolge der Ereignisse melden muss, damit man es exakt gegen das externe Modell des Systems prüfen kann, statt Wall-Clock-Zeit zu verwenden.
Ein interessantes Meta-Muster: Wenn man die schwierigere Aufgabe löst, wird das System am Ende einfacher.
Ein weiteres Beispiel: Wenn man annimmt, dass Festplatten ausfallen können, muss man ein Recovery-Protokoll einbauen und bekommt dadurch die Zustandssynchronisierung zurückgefallener Replikate praktisch „gratis“. Denn es ist exakt dasselbe Problem wie bei einer vollständig beschädigten Festplatte.
Im Artikel ist der Link zum Paper „Viewstamped Replication“ leider kaputt. https://pmg.csail.mit.edu/papers/vr-revisited.pdf lehnt die Verbindung ab.
Vermutlich muss es ein http-Schema statt https sein, also etwa http://pmg.csail.mit.edu/papers/vr-revisited.pdf.
Damit habe ich jetzt Lesestoff für Freitagabend.
Das VSR-2012-Paper ist eines meiner Lieblingspaper, und „Protocol-Aware Recovery for Consensus-Based Storage“ ist ebenfalls wirklich stark.
Viel Spaß beim Lesen.
Ich frage aus reinem Lerninteresse und hoffe, das wird nicht missverstanden. Ich arbeite mich gerade erst in verteilte Systeme ein und bin von deterministischem Simulation Testing fasziniert.
Nachdem ich den Jepsen-Bericht zu TigerBeetle, den zugehörigen Blogbeitrag und den Antithesis-Integrationscode im GitHub-Workflow kurz angeschaut habe, möchte ich den Testumfang besser verstehen.
Die Kernfrage ist, ob die Antithesis-Integration diese Bugs, die die Jepsen-Testsuite gefunden hat, ebenfalls hätte finden können.
Meine Frage beruht auf ein paar Annahmen, die falsch sein könnten. Ich dachte, TigerBeetle werde bereits umfassend mit der internen Testsuite und dem Antithesis-Produkt getestet, und ich hatte Antithesis-Testsuites als mächtiger als Jepsen verstanden. Deshalb war ich überrascht, dass Jepsen ein Problem gefunden hat, das Antithesis nicht gefunden hat.
Ich frage mich, ob mein Verständnis falsch ist. Konkret würde ich gern wissen, ob 1) die Antithesis-Testsuite diese konkrete Fehlerklasse nicht erkennen konnte, 2) dieser Teil des Systems noch nicht durch Antithesis-Tests abgedeckt war oder 3) ich die unterschiedlichen Stärken und Ziele von Jepsen- und Antithesis-Testsuites missverstehe und hier Äpfel mit Birnen vergleiche.
Auch der Jepsen-Testgenerator hat mit ziemlicher Sicherheit blinde Flecken. Genau deshalb hilft es, unterschiedliche Generatoren zu entwerfen.
Antithesis adressiert vor allem Problem 1 und stellt mit virtuellen Maschinen eine deterministische Simulationsumgebung bereit. Jepsen geht dasselbe Problem an, indem es echte Maschinen nutzt und Fehler auf Betriebssystemebene injiziert; TigerBeetles eigener VOPR ist zusammen mit der Datenbank so entworfen, dass ein ganzer Cluster in einem einzelnen Thread laufen kann. Diese drei Ansätze ergänzen sich und haben jeweils unterschiedliche Stärken.
Entscheidend bei diesem Bug waren die Punkte 2 und 3: einen Workload-Validator und Auditor zu schreiben, der den Bug tatsächlich auslösen kann. Hier haben 1.600 Zeilen TigerBeetle-spezifischer Clojure-Code von aphyr den Bug ausgelöst und erkannt; anschließend wurden auch die entsprechenden Tests auf TigerBeetle-Seite so gepatcht, dass sie ihn auslösen. Tatsächlich liegt der Bug hier eher im VOPR als in der Datenbank. Dass eine Datenbank Bugs hat, ist normal, und allein durch Willenskraft kann man Bugs nicht vermeiden. Deshalb braucht man eine Teststrategie, die die meisten Bugs auslösen kann; Bugs, die durchrutschen, weisen auf Mängel im Workload-Generator hin.
Antithesis nutzen wir ebenfalls, aber als zweite Schicht des deterministischen Simulation Testing.
Warum der Query-Engine-Bug durchgerutscht ist, siehe hier: https://tigerbeetle.com/blog/2025-06-06-fuzzer-blind-spots-m...
Ich frage mich, ob große Banken oder Börsen TigerBeetle einsetzen
Auf Unternehmensebene wird TigerBeetle bereits in der Produktion bei Kunden eingesetzt, die mehr als 100 Millionen Transaktionen pro Monat verarbeiten. Kürzlich wurde der erste Vertrag mit einem europäischen Fintech-Unicorn im Wert von 2 Milliarden US-Dollar abgeschlossen, und auch in den USA stehen mehrere Abschlüsse kurz bevor. Wegen des weltweiten Trends hin zur Echtzeit-Transaktionsverarbeitung [2] gibt es ziemlich viel Interesse von Unternehmen, die für höhere Performance zu TigerBeetle wechseln wollen.
Um die Frage zu beantworten: Einige Gründer von Clear Street, einem ziemlich großen Brokerage-Unternehmen an der Wall Street, haben in TigerBeetle investiert [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