
SQLite VFS mit kalten JOIN-Abfragen unter 100 ms von S3 + Seitenebenen-Komprimierung und -Verschlüsselung
turbolite ist ein SQLite-VFS in Rust, das Punktabfragen und Joins direkt von S3 mit einer Kaltstartlatenz von unter 250 ms ausführt.
Dieses Repository ist ein Cargo-Workspace mit zwei Crates:
turbolite – Reine Rust-Bibliothek. SQLite-VFS mit Seitenkomprimierung, Verschlüsselung und S3-Tiering.turbolite-ffi – C-FFI / ladbare Erweiterung + Sprachbindungen (Python, Node.js, Go).Es bietet außerdem seitenbasierte Komprimierung (zstd) und Verschlüsselung (AES-256) für Effizienz und Sicherheit im Ruhezustand, die unabhängig von S3 verwendet werden können.
Experimentell. turbolite wird aktiv weiterentwickelt und enthält Fehler. Sei vorsichtig.
Objektspeicher wird immer schneller. S3 Express One Zone liefert GETs im einstelligen Millisekundenbereich und Tigris ist ebenfalls extrem schnell. Die Lücke zwischen lokaler Festplatte und Cloud-Speicher schrumpft, und turbolite macht sich das zunutze.
Das Design und der Name sind inspiriert von turbopuffers Ansatz, konsequent um die Einschränkungen von Cloud-Speicher herum zu architektonieren. Das anfängliche Ziel des Projekts war es, Neons 500ms+ Kaltstarts zu schlagen. Ziel erreicht.
Wenn du eine Datenbank pro Server hast, verwende ein Volume. turbolite untersucht, wie man hunderte oder tausende von Datenbanken (eine pro Mandant, eine pro Arbeitsbereich, eine pro Gerät) haben kann, ohne ein Volume für jede zu benötigen, und mit einer einzigen Schreibquelle auskommt.
turbolite wird als Rust-Bibliothek, als ladbare SQLite-Erweiterung (.so/.dylib) und als Sprachpakete für Python und Node.js sowie GitHub-Abhängigkeiten für Go ausgeliefert. Jeder S3-kompatible Speicher funktioniert (AWS S3, Tigris, R2, MinIO, usw.). Es handelt sich um ein standardmäßiges SQLite-VFS, das auf Seitenebene arbeitet, daher sollten die meisten SQLite-Funktionen funktionieren: FTS, R‑Tree, JSON, WAL-Modus, usw.
turbolite ist Teil des breiteren hadb-Ökosystems. Das eigenständige turbolite ist ein Speicher-VFS mit einem einzigen sicheren Schreiber; wenn du HA-Leader-Election plus kontinuierliche WAL-Replikation möchtest, verwende es über haqlite-turbolite, das HaQLite und walrust darüberlegt. Dieser HA-Pfad ist noch sehr experimentell.
Wenn du zu turbolite beitragen oder Fehler finden möchtest, erstelle bitte einen Pull-Request oder öffne ein Issue.
| Abfrage | Typ | Kalt (S3 Express) | Kalt (Tigris) |
|---|---|---|---|
| Beitrag + Benutzer | Punktabfrage + Join | 86ms | 172ms |
| Profil | Multi-Table-Join (5 JOINs) | 251ms | 479ms |
| Wer hat geliked | Index-Suche + Join | 206ms | 302ms |
| Gemeinsame Freunde | Multi-Search-Join | 19ms | 49ms |
| Indizierter Filter | gedeckter Index-Scan | 79ms | 88ms |
| Vollscan + Filter | vollständiger Tabellenscan | 476ms | 532ms |
1 Mio. Beiträge / 100.000 Benutzer (~1,5 GB gespeichert) ohne Caching, jedes Byte von S3. EC2 c5.2xlarge + S3 Express One Zone (gleiche AZ, ~4 ms GET-Latenz). Fly performance-8x + Tigris (~25 ms GET-Latenz). Beide: 8 dedizierte vCPUs, 16 GB RAM, 7 Prefetch-Worker-Threads. Siehe Benchmarking und Speicher-Backend ist wichtig.
Benchmarks sind nach Cache-Ebene organisiert (was bei der Ausführung der Abfrage bereits auf der lokalen Festplatte ist):
| Cache-Ebene | Was gecached ist | Was von S3 geholt wird | Wann das passiert |
|---|---|---|---|
| none | nichts | alles | Frischer Start, leerer Cache |
| interior | innere B‑Tree-Seiten | Index + Datenseiten | Erste Abfrage nach Verbindungsaufbau |
| index | innere + Indexseiten | nur Datenseiten | Normaler turbolite-Betrieb |
| data | alles | nichts | Äquivalent zu lokalem SQLite |
interior ist der realistischste Kalt-Benchmark: innere Seiten werden beim Verbindungsaufbau eager geladen, sodass sie beim Ausführen der ersten Abfrage bereits gecached sind. Indexseiten werden beim ersten Zugriff im Hintergrund aggressiv prefetched und sind möglicherweise noch nicht bereit.
100.000 Zeilen, Fly.io performance-2x (dedizierte vCPU, NVMe, IAD):
| Operation | SQLite | turbolite | Overhead |
|---|---|---|---|
| Punktabfrage | 145K/s | 73K/s | 2,0x |
| Bereichsscan | 8,8K/s | 8,3K/s | Parität |
| Vollständiger Tabellenscan | 56/s | 60/s | Parität |
| INSERT | 19K/s | 23K/s | Parität |
| UPDATE nach PK | 40K/s | 27K/s | 1,5x |
| Batch-INSERT (in Txn) | 685K/s | 740K/s | Parität |
Punktabfragen haben den höchsten Overhead pro Seite (~2x). Alles andere erreicht oder übertrifft die Parität. Die lock‑freie Cache-Architektur bedeutet, dass gleichzeitige Lesevorgänge nie Schreibvorgänge blockieren.
| Nach | Lokal | S3 (gleiche Region RustFS) |
|---|---|---|
| 1.000 Inserts | 19ms | 38ms |
| 10.000 Batch | 17ms | 114ms |
| 1.000 Updates | 9ms | 36ms |
Schreibvorgänge sind immer lokal schnell. Die S3-Kosten fallen nur beim Checkpoint an. Zahlen mit RustFS in derselben Fly-Region (~2ms RTT). S3 Express One Zone wäre vergleichbar.
pip install turbolite
Please provide the Markdown content to translate.```python
import turbolite
conn = turbolite.connect("my.db", mode="s3",
bucket="my-bucket",
endpoint="https://t3.storage.dev")
conn.execute("CREATE TABLE users (id INTEGER PRIMARY KEY, name TEXT, email TEXT)")
conn.execute("INSERT INTO users VALUES (1, 'alice', '[email protected]')")
conn.commit()
alice = conn.cursor().execute("SELECT * FROM users").fetchone()
print(alice[1])
>>> "alice"
Siehe Installation für Node, Go, Rust, Nur-lokal-Modus und direkte Nutzung der .so-Erweiterung
turbolite ist für die Zwänge von S3 und nicht für Dateisystem-Zwänge ausgelegt. Jede Entscheidung leitet sich aus diesem Modell ab:
| S3-Einschränkung | Auswirkung |
|---|---|
| Hin- und Rückrufe sind langsam | Anzahl der Anfragen minimieren. Schreibvorgänge bündeln, aggressiv vorauslesen. |
| Bandbreite ist ein Engpass | Bandbreitenauslastung maximieren. |
| PUTs und GETs werden pro Vorgang berechnet | Ein 64-KB-GET kostet genauso viel wie ein 16-MB-GET. Anfragenanzahl optimieren, nicht Byte-Effizienz. |
| Objekte sind unveränderlich | Niemals an Ort und Stelle aktualisieren. Neue Versionen schreiben, einen Zeiger austauschen. Keine Korruption durch partielle Schreibvorgänge. |
| Speicher ist günstig | Nicht auf Platz optimieren. Überprovisionieren, alte Versionen behalten, später von der GC bereinigen lassen. |
turbolite fügt zwischen SQLite und S3 eine Introspections- und Indirektionsschicht ein, die Seiten effizient gruppiert, komprimiert, verfolgt und abruft.
SQLite verwendet einen B‑Tree‑Index und fordert jeweils eine Seite an. Es weiß, dass Seite N am Byte‑Offset N * page_size liegt. Und diese Seiten sind zufällig über die Pagemap verteilt, um effizienten wahlfreien Zugriff zu ermöglichen. Bei S3 würde das Abrufen einer Seite pro Anfrage jedoch Tausende potenziell zufällige GETs pro Abfrage bedeuten.
Aber Seiten sind nicht gleich geschaffen. SQLite hat verschiedene Seitentypen. turbolite trennt Seitengruppen nach Typ: innere B‑Tree‑Seiten, Index‑Blattseiten und Daten‑Blattseiten.