Was bringt die Rust-Engine von FalkorDB 6.0 konkret? Über mehr als 300 Benchmark-Abfragen hinweg führt die neue Engine 39 Prozent weniger CPU-Instruktionen aus als die abgelöste C-Engine. Dazu kommen 226 geschlossene Fehler, darunter 43 Abstürze und sechs Speichersicherheitsdefekte. Bestehende Cypher-Abfragen, APIs und Integrationen sollen ohne Änderung weiterlaufen. Wie diese Zahlen zustande kommen und was sie im Betrieb bedeuten, steht im Folgenden.
Eine Analogie hilft: Jede Abfrage ist ein Arbeitsauftrag in einer Werkstatt, jede CPU-Instruktion ein Handgriff. Es geht nicht darum, schneller zu arbeiten, sondern weniger oft hinzugreifen. Wer für dasselbe Ergebnis 39 Prozent weniger Handgriffe braucht, schafft mehr Aufträge pro Schicht oder dieselbe Arbeit mit weniger Personal. Bei Datenbankperformance zählt am Ende der Preis pro Abfrage, nicht der Rekord.
Was hinter dem Rust-Rewrite von FalkorDB 6.0 steckt
FalkorDB hat seinen Kern nach eigenen Angaben in 17 Monaten neu geschrieben, in Rust, mit rund 80.000 Zeilen Code aus 357 zusammengeführten Pull Requests. Die Begründung: Rust erzwingt Speichersicherheit beim Kompilieren und entfernt damit ganze Fehlerklassen, bevor der Code läuft. Gleichzeitig bleibt die Kontrolle über die unterste Ebene erhalten, die eine Graphdatenbank braucht. Intern galt eine feste Reihenfolge – erst lauffähig, dann stabil, dann schnell. Geschwindigkeit war also das letzte Ziel, nicht das erste.
Die Grundideen blieben unverändert: Graphen liegen als dünnbesetzte Matrizen im Speicher, Traversierungen laufen als Matrixmultiplikation. Deshalb soll sich der Umbau für Anwender kaum bemerkbar machen. Die neue Engine liest dieselben Datendateien wie die alte, bestehende Daten laden unverändert. Für Betreiber ist der Wechsel damit vor allem eine Frage des Deployments, nicht der Datenmigration.
Weniger CPU-Instruktionen pro Cypher-Abfrage: der Benchmark
Alle Performance-Zahlen stammen aus einem Messaufbau, der im FalkorDB-Repository neben dem Engine-Code liegt. Dort gilt eine harte Regel: Ein Ergebnis zählt nur, wenn es sich beim Nachmessen wiederholt. Ohne diese Bedingung werden aus Benchmarks schnell Wunschbilder.
Dasselbe Messprogramm fährt auch die alte C-Engine, sodass für jede Abfrage ein Verhältnis Rust zu C entsteht. Ein Wert unter 1,0x heißt: Die Rust-Engine braucht weniger Instruktionen für dieselbe Aufgabe. Eine Verschlechterung fällt so im Code-Review auf, ähnlich wie die Testsuite Verschlechterungen der Korrektheit abfängt. Ein Beispiel aus der veröffentlichten Tabelle: Bei count(DISTINCT …) sank der Aufwand von 36,2 Millionen auf 7,6 Millionen Instruktionen, das Verhältnis zur C-Engine von 1,93x auf 0,40x. Die Rust-Engine braucht dort also noch etwa zwei Fünftel der Instruktionen der Vorgängerin.
Was Batch-Ausführung und String-Interning konkret ändern
Der wichtigste strukturelle Unterschied ist der Wechsel von zeilenweiser zu spaltenweiser Verarbeitung, columnar batch execution genannt. Statt eine Zeile nach der anderen durch alle Auswertungsschritte zu schieben, verarbeitet die Engine ganze Chargen von Zeilen und wertet komplette Ausdrucksbäume spaltenweise aus. Im Werkstattbild: Der Auftrag wird nicht mehr einzeln durch jede Station getragen, sondern als Charge über ein Fließband geschoben. Ein arithmetischer Filter sank dadurch von 13,2 Millionen auf 4,6 Millionen Instruktionen, OR- und CASE-Konstrukte wurden 2,3- bis 2,6-mal günstiger.
Auch Kleinkram summiert sich. Konstante Funktionen werden einmal pro Charge ausgewertet statt pro Zeile, was Kombinationen aus split, trim und replace rund 3,8-mal günstiger macht. Die Frage nach einem Label beantwortet die Engine direkt als Spalte aus der Label-Matrix. Die Speicherbelegung pro 10.000-Zeilen-Scan fällt dadurch von 976 Kilobyte auf 12 Kilobyte – ein Faktor von über 80. String-Interning sorgt dafür, dass identische Zeichenketten nur einmal im Speicher liegen.
Unter der Haube kam außerdem Mehrversionsverwaltung hinzu, multi-version concurrency control. Sie sorgt dafür, dass Lesevorgänge nie blockieren und Schreibvorgänge konsistent bleiben. Bei einem Graphen mit vielen gleichzeitigen Lesern ist das oft wichtiger als die letzte Millisekunde im Benchmark.
Schreibpfad: Warum Löschen und Anlegen lange der Engpass war
Die veröffentlichte Tabelle zeigt, was viele Graphdatenbanken bremst: nicht die Traversierung, sondern das Schreiben. Ein neu gestalteter, seitenweise organisierter Kantenindex (paged edge-endpoint index) macht Schreibvorgänge auf einem Graphen mit zehn Millionen Kanten rund 114-mal billiger, weil nicht mehr der gesamte Index kopiert wird, sondern nur eine Seite. Das Entfernen einer ungenutzten Matrix lebender Knoten brachte beim Anlegen nach 500.000 Löschungen einen Sprung von 1,88 Millisekunden auf 0,019 Millisekunden.
Auch das Löschen selbst wurde umgebaut. Ein DELETE … RETURN auf einem Graphen mit 80.000 Kanten fiel von 1,39 Millisekunden auf 0,10 Millisekunden und ist damit erstmals unabhängig von der Graphgröße. Gelöschte IDs werden nach Rang zurückgewonnen, statt einen quadratisch wachsenden Durchlauf zu starten. Ein Planer-Fehler, der Traversierungsketten in umgekehrter Reihenfolge ausführte, kostete zuvor 34,4 Millionen Instruktionen; nach der Korrektur sind es 0,44 Millionen – ein Faktor von 78.
Am deutlichsten wird der Effekt bei kartesischen Produkten: Eine vierfache Verknüpfung brauchte vorher 2,5 Minuten und 20,8 Gigabyte Speicher, nach dem Umbau 25 Millisekunden und 28 Megabyte. Die C-Engine liegt dort bei 27 Millisekunden. Das ist der Unterschied zwischen einer Abfrage, die den Server umbringt, und einer, die im Hintergrund durchläuft.
Fehler, Abstürze und Replikation: was 6.0 an Zuverlässigkeit ändert
Die 226 geschlossenen Fehler sind der weniger glänzende, aber wichtigere Teil des Releases. Bevor eine Änderung von einem Menschen geprüft wurde, musste sie rund 1.585 openCypher-TCK-Szenarien, 1.322 Flow-Tests aus der Suite der Vorgängerengine und eine eigene Nebenläufigkeitssuite bestehen. Das Team betont, dass Ingenieure jede Designentscheidung selbst getroffen und jede Änderung selbst geprüft haben. Coding-Agenten übernahmen klar abgegrenzte Implementierungsarbeit innerhalb dieser Leitplanken.
Auch die Replikation wurde konkreter. Jeder Knoten, jede Kante, jedes Label und jedes Attribut kommt nun mit ID und Name zugleich an. Die Replik verwendet die vom Primär vergebene ID und bestätigt die Übereinstimmung, statt eine eigene zu erzeugen und zu hoffen, dass beide Seiten zusammenpassen. Wird eine Entität gelöscht, enthält der Datensatz die Labels, die sie trug. Ohne diese Information ließe sich das Löschen auf der Replik nicht korrekt anwenden.
Erhält die Replik etwas, das sie nicht erklären kann – ein unbekanntes Feld, eine Summe, die nicht aufgeht, oder eine Nutzlast mit falscher Prüfsumme –, lehnt sie die Änderung sofort ab und meldet das. Bewusst konservativ: lieber ein sichtbarer Fehler als ein stiller Datenunterschied, den niemand mehr nachvollziehen kann.
Grenzen von 6.0 und der Weg in den eigenen Betrieb
Eine Einschränkung: FalkorDB 6.0 enthält noch keinen unterstützten Upgrade-Pfad von Version 4.x. Der Wechsel in beide Richtungen kommt erst mit 6.2. Bis dahin empfiehlt das Team, 6.0 auf neuen Deployments oder parallel zur bestehenden Installation zu betreiben. Wer eine produktive Graphdatenbank mit Bestandsdaten migrieren will, sollte auf 6.2 warten oder den Parallelbetrieb von Anfang an einplanen.
Verfügbar ist die Version ab sofort über Docker Hub; in FalkorDB Cloud erfolgt die Ausrollung schrittweise, während Rückmeldungen gesammelt werden. Für die Bewertung im eigenen Haus gilt derselbe Grundsatz wie für den Benchmark: Ein Ergebnis zählt nur, wenn es sich reproduzieren lässt. Fahr die Abfragen, die dich wirklich kosten – schwere Aggregationen, Schreiblast beim Laden, Löschvorgänge –, gegen beide Engines und schau auf das Verhältnis, nicht auf die schönste Einzelzahl.
39 Prozent weniger CPU-Instruktionen bedeuten nicht automatisch 39 Prozent mehr Durchsatz. Aber pro Abfrage fällt weniger Rechenzeit an, was sich in dichter gepackten Kernen, kleineren Instanzen und weniger Hitze bei Lastspitzen niederschlägt. Wichtiger ist ohnehin die Verschiebung: Fehlerklassen, die eine Sprache beim Kompilieren ausschließt, und ein Schreibpfad, der nicht mehr mit der Graphgröße wächst, sind Fortschritte, die man nicht in einer Benchmark-Tabelle sieht – sondern erst nach Wochen im Betrieb ohne Vorfall.
Quelle: falkordb.com
