Eine Time-Series-DB von Grund auf selbst bauen
(nakabonne.dev)-
In Go geschrieben, aber weitgehend sprachunabhängig
-
Time-Series-Daten sind eine Sammlung mehrerer Werte mit Zeitstempel. Jeder Eintrag ist ein Datenpunkt
→ Sehr große Datenmengen. Aussagekräftig werden sie erst durch ihre Menge. Häufig werden sie auch millionenfach pro Sekunde erfasst
→ Append-only, nach Zeit sortiert, aktuelle Daten zuerst
→ Bulk-Reads für bestimmte Zeiteinheiten
→ High Cardinality (die Menge der Serien ist sehr groß)
→ In den meisten Fällen werden vor allem aktuelle Daten gelesen und genutzt
-
Entwicklung der TStorage-DB-Engine-Bibliothek in Go, ausgelegt auf die überwiegend schreibintensive Natur von Time-Series-Daten
-
Datenmodell
→ Lineares Datenmodell
→ Partitionierung der Datenpunkte nach Zeiteinheiten
→ Jede Partition arbeitet wie eine separate, unabhängige DB, die alle Daten innerhalb dieses Zeitraums enthält
→ Nur die Head-Partition und die direkt folgende Partition können als Memory-Partitionen im Heap gehalten werden
→ Zur Vermeidung von Datenverlust wird vor dem Schreiben in das WAL (Write Ahead Log) geschrieben
→ Ältere Partitionsdaten werden als einzelne Datei auf der Festplatte gespeichert. Disk-Partitionen sind schreibgeschützt
- Memory-Partition
→ Die Liste der Datenpunkte wird im Heap als Array dargestellt (ähnlich wie Go-Slices)
→ Wegen Latenz und Synchronisation tritt Out-of-order häufig auf. Innerhalb derselben Partition kann beim Speichern durch Buffering neu sortiert werden; bei anderen Partitionen ist es möglich, sie hinter einer früheren statt der Head-Partition anzuhängen
→ Es werden genau dieselben Daten gespeichert wie tatsächlich im WAL, damit auch bei Fehlern eine Wiederherstellung möglich ist
- Disk-Partition
→ Pro Partition werden Metadaten und die komprimierten eigentlichen Daten in einem Verzeichnis gespeichert (eine verkleinerte Version von Prometheus V3 Storage)
→ Memory-Mapped-Datenformat (kann vom Kernel per mmap gecacht werden)
→ Die Metadaten bilden einen Index im JSON-Format
- Für die Datenkodierung, dargestellt als Tupel aus Zeitstempel und Wert, wird das im Gorilla-Paper von Facebook vorgeschlagene Kodierungsverfahren verwendet
→ Zeitstempel und Werte werden mit unterschiedlichen Methoden kodiert
→ timestamp ist ein unsigned 64-bit integer und verwendet Delta-of-delta-Encoding
→ Delta-Encoding: Es wird nur die Differenz zwischen vorherigem und aktuellem Wert gespeichert
→ Delta-of-Delta-Encoding: Da Werte meist in festen Zeitabständen entstehen, wird nur die Differenz der Deltas gespeichert
→ Da variabel lang kodiert wird, benötigt Delta-of-Delta den wenigsten Speicherplatz
→ values sind signed 64-bit floating-point-Werte und verwenden XOR-Encoding
→ Der erste Wert wird einfach gespeichert
→ Der nächste Wert wird per XOR verglichen; ist das Ergebnis 0, ist er identisch zum vorherigen Wert und es wird nur ein einzelnes 0-Bit gespeichert
→ Ist das Ergebnis nicht 0, wird anhand der anderen Bits weitergerechnet (Meaningful Bit)
→ Führende und nachfolgende Nullen werden bestimmt; ist ihre Anzahl gleich, werden nur die Nullen und die bedeutungsvollen Bits gespeichert, andernfalls die Anzahl der führenden Nullen, die Anzahl der Meaningful Bits und deren Inhalt
Noch keine Kommentare.