Einführung in die grundlegende Architektur und Prinzipien von RocksDB

Rocksdb

Flink bietet flussbasiertes Stateful Computing. Neben der Bereitstellung von Echtzeit-Datenflussverarbeitungsfunktionen muss auch der durch die Berechnung generierte Status gespeichert werden.
Um die Anforderungen an den Statuszugriff zu erfüllen, werden drei Arten von Statusspeichermechanismen bereitgestellt: Speicher, Flie-System und Rocksdb.
Der Speicherzugriff ist effizient, der Speicherplatz ist begrenzt und die Verfügbarkeit gering.
Das Dateisystem bietet Statuspersistenzfähigkeit, aber eine geringe Zugriffsleistung.
rocksdb bietet schnelle Datenschreib- und Datenpersistenzfunktionen.
In diesem Artikel wird die grundlegende Architektur des Rocksdb-Designs vorgestellt.

Einführung in RocksDB

Rocksdb ist eine leistungsstarke kv-persistente Speicher-Engine, die auf Google LevelDB basiert. Sie ist als Bibliothekskomponente in das Programm eingebettet und bietet Optimierung für große verteilte Anwendungen, die auf SSD ausgeführt werden. RocksDB bietet keine übergeordneten Vorgänge wie Sicherung, Lastausgleich, Snapshots usw., sondern stellt stattdessen Tool-Unterstützung bereit und übergibt die Implementierung an Anwendungen der oberen Ebene. Es ist dieser hohe Grad an Anpassbarkeit, der es ermöglicht, RocksDB an eine Vielzahl von Anforderungen und Workload-Szenarien anzupassen.

RocksDB-Architektur

RocksDB verwendet Log-Structured Merge (LSM)-Bäume als grundlegende Datenspeicherstruktur.

RocksDB-Hauptkomponenten und Flussdiagramm der Lese-, Schreib- und Komprimierungsvorgänge
RocksDB-Hauptkomponenten und Flussdiagramm der Lese-, Schreib- und Komprimierungsvorgänge

Schreibt

Wenn Daten in RocksDB geschrieben werden, werden sie zunächst in den Schreibcache MemTable im Speicher und in das Write-Ahead-Log (WAL) auf der Festplatte geschrieben.
Immer wenn die Menge der zwischengespeicherten Daten in MemTable den voreingestellten Wert erreicht, werden MemTable und WAL in einen unveränderlichen Zustand konvertiert, und neue MemTable und WAL werden für das nachfolgende Schreiben zugewiesen, und dann wird derselbe Schlüssel in der unveränderlichen MemTable zusammengeführt und geleert auf
die Festplatte in der Datei „Sorted String Table“ (ssTable) oben und verwerfen Sie die zugehörigen MemTable- und WAL-Daten.

1. Um die Reihenfolge der Daten und die Effizienz der Dateneinfügung und -suche (O(log n)) sicherzustellen, wird MemTable basierend auf SkipList implementiert.
2. WAL wird zur Datenwiederherstellung verwendet, wenn ein Fehler auftritt, und kann ausgeschaltet werden.
3. Zusätzlich zum Datenblock (DataBlock) verfügt jede ssTable auch über einen Indexblock (IndexBlock) für die binäre Suche

Verdichtung

Der LSM-Baum hat mehrere Ebenen und jede Ebene besteht aus mehreren ssTables. Die neueste ssTable wird auf Ebene 0 (der obersten Ebene) platziert und die untere ssTable wird durch den Komprimierungsvorgang
erstellt. Die Gesamtgröße der ssTable jeder Ebene wird durch die Konfigurationsparameter bestimmt. Wenn die Datengröße der L-Ebene den voreingestellten Wert überschreitet, wird die SSTable der L-Ebene ausgewählt, um mit dem überlappenden Teil der SSTable der L zusammenzuführen +1 Ebene. Durch diesen Prozess werden die geschriebenen Daten von Level-
0 schrittweise auf die letzte Ebene übertragen. Basierend auf diesen Vorgängen werden das Löschen und Überschreiben von Daten abgeschlossen, während der Datenraum und die Leseleistung optimiert werden.

Komprimierungsvorgänge sind für E/A effizient, da die Komprimierung parallel durchgeführt werden kann und Datendateien stapelweise gelesen und geschrieben werden.

Die Schlüssel in einer einzelnen ssTable in Level-0 sind geordnet und es gibt Schlüsselüberschneidungen in verschiedenen ssTables. Die Schlüssel in der unteren Ebene sind insgesamt geordnet.

RocksDB unterstützt mehrere Komprimierungstypen:

  1. Abgestufte Komprimierung: Durch die LevelDB-Migration verbessert, wächst die Größe jeder Ebene exponentiell von oben nach unten und die Komprimierung beginnt, wenn die Datenmenge die angegebene Größe erreicht.
  2. Tiered Compaction: Auch Universal Compaction genannt, ähnelt sie der von Apache Cassandra/HBase verwendeten verzögerten Komprimierung. Die Komprimierung beginnt, wenn die Anzahl der Läufe/ssTables einer bestimmten Ebene den voreingestellten Wert oder das Verhältnis der Datenbankgröße zur Größe von überschreitet Die größte Schicht überschreitet den voreingestellten
    Koeffizienten.
  3. FIFO-Komprimierung Sobald die Datenmenge den voreingestellten Wert erreicht, werden alte Daten verworfen und eine leichte Komprimierung durchgeführt, die hauptsächlich in Speicher-Caching-Szenarien verwendet wird.

Durch die Wahl des Komprimierungsmodus eignet sich RocksDB für eine Vielzahl von Szenarien. Durch Anpassen der Komprimierungsstrategie kann RocksDB für spezielle Cache-Arbeiten lesefreundlich, schreibfreundlich oder extrem schreibfreundlich konfiguriert werden.
Entwickler müssen die Indikatorkonfigurationen entsprechend den Nutzungsszenarien abwägen. Der verzögerte Komprimierungsalgorithmus kann die Schreibverstärkung und den Schreibdurchsatz reduzieren, aber die Leseleistung wird beeinträchtigt; während die aggressive Komprimierungsstrategie die Schreibleistung beeinträchtigt, aber die Leseeffizienz höher ist.
Protokoll- und Stream-Verarbeitungsdienste können seitliches Umschreiben verwenden, während Datenbankdienste ein Gleichgewicht zwischen Lesen und Schreiben herstellen müssen.

Vergleich der Auswirkungen von drei Hauptkomprimierungsstrategien auf verschiedene Indikatoren
Vergleich der Auswirkungen von drei Hauptkomprimierungsstrategien auf verschiedene Indikatoren

Liest

Beginnen Sie mit der Suche in MemTables und suchen Sie dann nacheinander von Ebene 0 bis zur unteren Ebene, bis der angegebene Schlüssel gefunden wird. Wenn er nicht gefunden wird, existiert er nicht.
Die Suche auf jeder Ebene des LSM verwendet die binäre Suche, um die Ziel-ssTables zu durchsuchen, verwendet dann den Bloom-Filter, um nicht benötigte durchsuchte ssTables herauszufiltern, und
findet schließlich den Wert des angegebenen Schlüssels in der ssTable durch binäre Suche.

Kernstruktur

MemTable

MemTable ist eine speicherinterne Datenstruktur, die dazu dient, die gerade geschriebenen Daten aufzubewahren, bis sie in die SST-Datei geschrieben werden.
Es bedient sowohl Lese- als auch Schreibvorgänge: Neue Schreibvorgänge fügen immer Daten in Memtable ein; während Leseprozesse zuerst Memtable abfragen, da die Daten in Memtable neuer sind.

Sobald eine Memtable voll ist, wird sie unveränderlich und durch eine neue Memtable ersetzt. Der Hintergrundthread aktualisiert den Inhalt der Speichertabelle in der SST-Datei und zerstört dann die auf der Festplatte abgelegte Speichertabelle.

memtable wird standardmäßig mit SkipList implementiert. Sie können auch HashLinkList, HashSkipList und Vector auswählen, um einige Abfragen zu beschleunigen.

  • SkipList MemTable-
    Lese- und -Schreibvorgänge, Direktzugriff und sequentielle Scans bieten insgesamt eine gute Leistung und bieten außerdem einige andere nützliche Funktionen, die derzeit von anderen Memtable-Implementierungen nicht unterstützt werden, wie z. B. gleichzeitige Einfügungen und Einfügungen mit Treffern

  • HashSkipList MemTable
    HashSkipList organisiert Daten in einer Hash-Tabelle, jeder Hash-Bucket ist eine geordnete SkipList und der Schlüssel ist der Präfixschlüssel, der vom Originalschlüssel über Options.prefix_extractor abgefangen wird. Es wird hauptsächlich verwendet, um die Anzahl der Vergleiche während der Abfrage zu reduzieren. Wird im Allgemeinen in Verbindung mit dem PlainTable SST-Format verwendet, um Daten in RAMFS zu speichern.
    Die größte Einschränkung von Hash-basierten Memtables besteht darin, dass das Scannen über mehrere Präfixe hinweg ein Kopieren und Sortieren erfordert, was sehr langsam und speicherintensiv ist.

Szenarien, die Memtable dazu veranlassen, die Festplatte zu aktualisieren:

  1. Die Memtable-Größe überschreitet ColumnFamilyOptions::write_buffer_size nach dem Schreiben
  2. Die Memtable-Nutzung aller Spaltenfamilien überschreitet DBOptions::db_write_buffer_size oder write_buffer_manager sendet ein Aktualisierungssignal. Die größte MemTable wird geleert
  3. Die WAL-Dateigröße überschreitet DBOptions::max_total_wal_size

Cache blockieren

Wo RocksDB Daten zum Lesen im Speicher zwischenspeichert. Ein Cache-Objekt kann von mehreren RocksDB-Instanzen im selben Prozess gemeinsam genutzt werden, und Benutzer können die gesamte Cache-Kapazität steuern.
Der Blockcache speichert unkomprimierte Blöcke. Benutzer können optional einen sekundären Blockcache einrichten, der komprimierte Blöcke speichert. Bei einem Lesevorgang wird der Datenblock zuerst aus dem unkomprimierten Blockcache und dann aus dem komprimierten Blockcache abgerufen. Bei Verwendung von Direct-IO kann der komprimierte Blockcache den Betriebssystemseitencache ersetzen.

Block Cache verfügt über zwei Cache-Implementierungen, nämlich LRUCache und ClockCache. Beide Arten von Caches verwenden Sharding, um Sperrenkonflikte zu entschärfen. Die Kapazität wird jedem Shard gleichermaßen zugewiesen, und Shards teilen sich die Kapazität nicht. Standardmäßig ist jeder Cache in bis zu 64 Fragmente unterteilt, und die Kapazität jedes Fragments beträgt mindestens 512 KB.

  • LRUCache: Die Standard-Cache-Implementierung. Verwendet einen 8 MB großen LRU-basierten Cache. Jeder Shard des Caches verwaltet seine eigene LRU-Liste und seine eigene Hash-Tabelle für Suchvorgänge. Die Synchronisierung wird durch den Mutex jedes Shards erreicht, und sowohl Lookups als auch Einfügungen müssen den Shard sperren.

In seltenen Fällen, wenn Blöcke gelesen oder iteriert werden und die feste Gesamtblockgröße den Grenzwert überschreitet, ist die Größe des Caches möglicherweise größer als die Kapazität. Wenn der Host nicht über genügend Speicher verfügt, kann dies zu unerwarteten OOM-Fehlern führen, die zum Absturz der Datenbank führen können

  • ClockCache: ClockCache implementiert den CLOCK-Algorithmus. Jeder Abschnitt des Takt-Cache verwaltet eine kreisförmige Liste von Cache-Einträgen. Der Clock-Handler durchläuft die Round-Robin-Liste und sucht nach nicht angehefteten Einträgen zum Entfernen, gibt aber auch jedem Eintrag eine zweite Chance, im Cache zu bleiben, wenn er seit dem letzten Scan verwendet wurde.

ClockCache ist noch nicht stabil, nicht empfohlen

Schreiben Sie den Puffermanager

Der Write Buffer Manager wird verwendet, um die gesamte Speichertabellennutzung mehrerer Spaltenfamilien oder mehrerer Datenbankinstanzen zu steuern.
Verwendung: Der Benutzer erstellt ein Schreibpuffer-Manager-Objekt und übergibt das Objekt an die Spaltenfamilie oder Datenbankinstanz, die den Speicher steuern muss.

Es gibt zwei Einschränkungen:

1. Begrenzen Sie die Gesamtspeichernutzung von Memtables

Das Auslösen einer dieser Bedingungen löst einen Flush-Vorgang für die Spaltenfamilie der Instanz aus:

  1. Wenn die aktive Memtables-Nutzung 90 % des Schwellenwerts überschreitet
  2. Wenn der Gesamtspeicher den Grenzwert überschreitet und die Nutzung aktiver Mamtables 50 % des Schwellenwerts überschreitet.
2. Die Speichernutzung von Memtable wird in den Blockcache übertragen

In den meisten Fällen sind die tatsächlich im Blockcache verwendeten Blöcke viel kleiner als die im Blockcache zwischengespeicherten Blöcke. Wenn der Benutzer diese Funktion aktiviert, deckt die Blockcachekapazität die Speichernutzung sowohl des Blockcaches als auch der Memtable ab.
Wenn der Benutzer gleichzeitig „cache_index_and_filter_blocks“ aktiviert, befindet sich die Speichernutzung der drei Hauptspeicherbereiche von RocksDB (Index- und Filtercache, Memtables und Blockcache) vollständig im Blockcache.

SST-Dateiformat

BlockBasedTable ist das Standardtabellenformat für SSTables.

<beginning_of_file>
[data block 1]
[data block 2]
...
[data block N]
[meta block 1: filter block]                  (see section: "filter" Meta Block)
[meta block 2: index block]
[meta block 3: compression dictionary block]  (see section: "compression dictionary" Meta Block)
[meta block 4: range deletion block]          (see section: "range deletion" Meta Block)
[meta block 5: stats block]                   (see section: "properties" Meta Block)
...
[meta block K: future extended block]  (we may add more meta blocks in the future)
[metaindex block]
[Footer]                               (fixed size; starts at file_size - sizeof(Footer))
<end_of_file>

Datenblock DataBlock: Die Folge von Schlüssel-Wert-Paaren wird gemäß den Sortierregeln geordnet und in eine Reihe von Datenblöcken (Datenblöcken) unterteilt. Diese Blöcke werden nacheinander am Anfang der Datei angeordnet und jeder Datenblock wird optional komprimiert.

Metadatenblock MetaBlock: Dem Datenblock folgt eine Reihe von Metadatenblöcken (Metablock). Zu den Metadatenblöcken gehören: Filterblock (Filterblock), Indexblock (Indexblock), Komprimierungswörterbuchblock (Komprimierungswörterbuchblock), Bereich Löschblock (Bereichslöschblock), Attributblock (Eigenschaftsblock).

Metaindex 3 Blöcke MetaIndexBlock: Der Metaindexblock enthält eine Zuordnungstabelle, die auf jeden Metablock zeigt. Der Schlüssel ist der Name des Metablocks, der Wert ist der Zeiger auf den Metablock und der Zeiger zeigt über den Offset auf den Datenblock und Größe.

Fußzeile: Am Ende der Datei befindet sich eine Fußzeile mit fester Länge. Einschließlich eines Zeigers auf den Metaindexblock, eines Zeigers auf den Indexblock und einer magischen Zahl.

Spezifische Arten von Metablöcken:
Indexblock Indexblock

Der Indexblock wird verwendet, um den Datenblock zu finden, der den angegebenen Schlüssel enthält. Es handelt sich um eine Datenstruktur, die auf der binären Suche basiert. Abhängig von der Nutzungskonfiguration kann eine Datei einen einzelnen Indexblock oder eine Reihe partitionierter Indexblöcke enthalten. Das heißt, es gibt zwei Indexmethoden: den globalen Index und den Partitionsindex.

Filterblock Filterblock

Globale Filter und Partitionsfilter werden durch Bloom-Filter implementiert

  1. Globaler Filter Vollfilter: In diesem Filter gibt es nur einen Filterblock für die gesamte SST-Datei.
  2. Partitionierter Filter: Der vollständige Filter ist in mehrere Unterfilterblöcke unterteilt. Oben in diesen Blöcken befindet sich ein Indexblock zum Zuordnen von Schlüsseln zu entsprechenden Unterfilterblöcken.
Komprimierungswörterbuchblock. Komprimierungswörterbuchblock

Enthält ein Wörterbuch, das zur Vorbereitung der Komprimierungsbibliothek vor dem Komprimieren/Dekomprimieren jedes Blocks verwendet wird.

Bereichslöschblock Bereichslöschblock

Der Bereichslöschblock enthält den Löschbereich im Schlüssel und die Seriennummer in der Datei. Wenn die Leseanforderung an sst gesendet wird, kann anhand des angegebenen Bereichs in sst beurteilt werden, ob der Schlüssel im Bereich von deleterange liegt. Wenn er vorhanden ist, wird NotFound direkt zurückgegeben. Es gibt auch einen Bereich in der Memtable, der die gleiche Funktion ausführt.
Veraltete Tombstone-Daten werden während der Komprimierung oder Spülung gelöscht.

Eigenschaftenblock Eigenschaftenblock

Enthält Attributinformationen.
Format des Statistikblocks:

 [prop1] 每个property都是一个键值对    
 [prop2]
 ...
 [propN]

Es wird garantiert, dass die Attributinformationen sequentiell sind und sich nicht wiederholen. Standardmäßig sind die folgenden Informationen enthalten:

 data size               // data block总大小
 index size              // index block总大小
 filter size             // filter block总大小
 raw key size            // 所有key的原始大小
 raw value size          // 所有value的原始大小
 number of entries
 number of data blocks

Optimierung

Der Entwicklungsprozess der RocksDB-Optimierung:

  1. Optimierung der Schreibverstärkung: Log-Structure Merge Tree
  2. Raumvergrößerung: Verdichtungsvorgang
  3. Reduzieren Sie die durch Komprimierung verursachte CPU-Last: Optimieren Sie lsm und steuern Sie die Granularität der Komprimierungsfrequenz
  4. CPU-, SSD-Ressourcenbilanz: Speicher aufteilen, Remote-Speicher verwenden (HDFS, S3, OSS)

Schreibverstärkung

RocksDB konzentrierte sich schon früh auf die Reduzierung der Schreibverstärkung durch Einsparung von Flash-Löschzyklen. Die Schreibverstärkung erfolgt hauptsächlich auf zwei Ebenen:

1. Die von der SSD selbst eingeführte Schreibverstärkung beträgt 1,1 bis 3;

2. Speicher- und Datenbanksoftware erzeugen auch eine Schreibverstärkung, manchmal bis zu 100 (z. B. wenn eine 100-Byte-Änderung dazu führt, dass eine 4-KB-/8-KB-/16-KB-Seite geschrieben wird).

Leveled Compaction bringt normalerweise eine Schreibverstärkung zwischen 10 und 30, was in den meisten Fällen niedriger ist als bei B-Bäumen, aber immer noch zu hoch für schreibempfindliche Anwendungen.
Bei der Tiered Compaction wird also die Leseleistung geopfert, um die Schreibverstärkung auf 4–10 zu reduzieren. Szenarien mit hohen Datenschreibraten verwenden Komprimierungsstrategien wie Tiered Compaction, um die Schreibverstärkung zu reduzieren, und
Szenarien mit niedrigen Schreibraten verwenden Strategien wie Leveled Compaction, um den Speicherplatzverbrauch zu reduzieren und die Leseeffizienz zu verbessern.

Auswirkung der Schreibverstärkung auf die Schreibrate
Auswirkung der Schreibverstärkung auf die Schreibrate

Raumvergrößerung

Eine anschließende Beobachtung der meisten Programme zeigt, dass der Schreibzyklus und der Schreib-Overhead des Flash-Speichers nicht eingeschränkt sind und die E/A-Last weitaus geringer ist als die Kapazität, die SSD bieten kann.
Die Speicherplatznutzung wird wichtiger als die Schreibverstärkung, also beginnen Sie mit der Optimierung des Festplattenspeichers.

Dank des nicht fragmentierten Datenlayouts der LSM-Baumstruktur kann sie auch eine effektive Rolle bei der Optimierung des Speicherplatzes spielen. Leveled-Compaction kann durch die Reduzierung schmutziger Daten (Löschen/Überschreiben) in LSM-Bäumen optimiert werden.
Daher die neue Datenkomprimierungsstrategie:

Dynamische Leveled Compaction: Die Datengröße jeder Ebene wird dynamisch entsprechend der tatsächlichen Größe der vorherigen Ebene angepasst, wodurch eine bessere und stabilere Platzeffizienz als bei Leveled Compaction erreicht wird

Wie in den Testdaten in der Abbildung unten rechts gezeigt, belegt Leveled Compaction 25,6 % des Platzes, während die Dynamic Leveled Compaction-Strategie nur 12,4 % benötigt.
In extremen Fällen kann die Festplattennutzung der Leveled Compaction bis zu 90 % betragen, während die Dynamic Leveled Compaction immer noch in einem relativ stabilen Bereich bleiben kann.

Speicherplatznutzung und Datengröße von zwei Komprimierungsstrategien bei einer konstanten Schreibrate von 2 MB/s
Speicherplatznutzung und Datengröße von zwei Komprimierungsstrategien

CPU-Auslastung

Durch die Reduzierung der CPU-Last kann die Leistung einer kleinen Anzahl CPU-gebundener Anwendungen verbessert werden. Noch wichtiger ist, dass durch die Reduzierung des CPU-Overheads Hardwarekosten eingespart werden können.
Zu den ersten Möglichkeiten zur Reduzierung des CPU-Overheads gehören: Einführung von Präfix-Bloom-Filtern, Anwendung von Bloom-Filtern vor Indexabfragen und Optimierung von Bloom-Filtern

Anpassung an neue Hardware-Technologie

SSD: Architekturverbesserungen im Zusammenhang mit SSD können sich auf RocksDB auswirken. Beispielsweise versprechen Open-Channel-SSDs, Multi-Stream und SSDZNS eine Verbesserung der Abfragelatenz und eine Reduzierung der Flash-Löschzyklen.
Da die meiste Software, die RocksDB verwendet, durch den Speicherplatz und nicht durch Löschzyklen und Latenz begrenzt ist, wird diese neue technische Änderung nur für eine kleine Anzahl von Software, die RocksDB verwendet, die Leistung verbessern.
Die direkte Anpassung von RocksDB an neue Hardwaretechnologien wird die konsistente Erfahrung mit RocksDB in Frage stellen. Derzeit gibt es in der Community keinen Forschungs- und Optimierungsplan zum Thema Speicher-Computing.

Disaggregierter (Remote-)Speicher: Remote-Speicher hat derzeit Priorität. Die aktuelle Optimierung besteht darin, den Flash-Speicher in der lokalen Umgebung voreinzustellen, aber das aktuelle Netzwerk ermöglicht die Unterstützung von mehr Remote-I/O.
Daher wird für immer mehr Programme die Leistung von RocksDB zur Unterstützung von Remote-Speicher immer wichtiger. Remote-Speicher kann bei Bedarf konfiguriert werden, was die Wiederverwendung von CPU- und SSD-Ressourcen erleichtert.
Zu den aktuellen Optimierungen für separaten Speicher gehören: Integration und Parallelisierung von I/O zur Optimierung der I/O-Latenz, Weitergabe von QoS-Anforderungen an das zugrunde liegende System und Berichterstellung von Analyseinformationen

Speicherklassenspeicher (SCM: Speicherklassenspeicher, der sowohl die Vorteile des Speichers als auch die Eigenschaften des Speichers aufweist. Derzeit gibt es mehrere Anwendungsideen:

  1. Als Speichererweiterung geht es beim SCM darum, eine Datenstruktur zu entwerfen, die zu den beiden Speichertypen passt
  2. SCM wird als Hauptspeicher der Datenbank verwendet
  3. Wenden Sie SCM auf WAL an

Rocksdb-Nutzungsoptimierung auf großen Systemen

Schlüssel-Wert-Schnittstelle

Nahezu jede Speicher-Workload kann von einem Datenspeicher mit einer KV-API bedient werden. Die KV-Schnittstelle ist generisch.
Sowohl Schlüssel als auch Wert bestehen aus Byte-Arrays variabler Länge. Die Anwendung ist für das Parsen und Interpretieren des Schlüssels und Werts verantwortlich und kann frei wählen, welche Informationen in den Schlüsselwert gepackt werden sollen, einschließlich des Codierungsschemas.
Ein weiterer Vorteil der KV-Schnittstelle ist die Portabilität, die die Migration von Daten zwischen Schlüsselwertsystemen erleichtert.

Allerdings kann die KV-Schnittstelle die Leistung einiger Programme einschränken. Beispielsweise ist es schwierig, eine effiziente Leistung durch den Aufbau einer Parallelitätskontrolle außerhalb von RocksDB zu erzielen, insbesondere in Szenarien, in denen ein zweiphasiges Festschreiben unterstützt werden muss, und einige Daten müssen vor dem Festschreiben einer Transaktion beibehalten werden, sodass RocksDB Transaktionsunterstützung bietet.

Version und Zeitstempel

Die Versionskontrolle von Daten ist sehr wichtig. Versionsinformationen sind in RocksDB das Erste, um Funktionen wie Multi-Version-Parallelitätskontrolle (MVCC), Point-in-Time-Lesevorgänge usw. ordnungsgemäß zu unterstützen.
RocksDB muss außerdem einen effizienten Zugriff auf verschiedene Versionen unterstützen.

Derzeit verwendet RocksDB intern 56-Bit-Sequenznummern, um Schlüssel-Wert-Paare verschiedener Versionen zu identifizieren. Sequenznummern werden von RocksDB generiert und jedes Mal erhöht, wenn ein Client schreibt, sodass alle Daten in einer logischen Reihenfolge vorliegen.
Mit RocksDB können Anwendungen Snapshots der Datenbank erstellen. RocksDB garantiert, dass alle zum Zeitpunkt des Snapshots vorhandenen Schlüssel-Wert-Paare bestehen bleiben, bis das Programm den Snapshot explizit freigibt. Daher können mehrere Schlüssel-Wert-Paare mit demselben Schlüssel nebeneinander existieren. durch ihre Sequenznummern unterschieden.

Auch diese Art der Versionskontrolle weist Einschränkungen auf und kann den Anforderungen vieler Programme nicht gerecht werden.

  1. Da es keine API zur Angabe eines Zeitpunkts gibt, unterstützt RocksDB das Erstellen vergangener Snapshots nicht. Außerdem ist die Unterstützung von Point-in-Time-Lesevorgängen ineffizient
  2. Jede RocksDB-Instanz verwaltet ihre eigene Sequenznummer und Snapshots können nur pro Instanz erstellt werden. Die Komplexität der Programmversionskontrolle, die zu einer Fragmentierung mehrerer Daten führt, nimmt zu. Es ist grundsätzlich unmöglich, Datenversionen bereitzustellen, die über Shards hinweg konsistent gelesen werden.

Anwendungen können diese Einschränkung umgehen, indem sie den Schreibzeitfehler im Schlüssel/Wert kodieren. Diese Methode führt jedoch zu einer Leistungsverschlechterung. Die Codierung im Schlüssel beeinträchtigt die Leistung der Punktsuche (der Schlüssel wird größer); die Codierung
im Wert beeinträchtigt die Leistung desselben Schlüssels beim Schreiben außerhalb der Reihenfolge. und erschweren das Lesen des alten Versionsschlüssels (Wert dekodieren, Zeitstempel vergleichen). Diese Einschränkungen können besser gelöst werden, indem die Anwendung den Zeitstempel angeben lässt und die Anwendung die Daten zusätzlich zum Schlüssel/Wert mit einem globalen Zeitstempel markieren kann.

Resourcenmanagement

Bei umfangreichen verteilten Datendiensten werden Daten häufig in mehrere Fragmente aufgeteilt und zur Speicherung auf mehrere Knoten verteilt. Für die Bereitstellung jedes Shards wird eine separate RocksDB-Instanz verwendet.
Das bedeutet, dass auf dem Host viele RocksDB-Instanzen laufen. Diese Instanzen können alle in einem einzigen Adressraum oder jede in ihrem eigenen Adressraum ausgeführt werden.

1. RocksDB muss Ressourcen effektiv verwalten, um sicherzustellen, dass sie effektiv genutzt werden. Wenn es im Einzelprozessmodus ausgeführt wird, muss es in der Lage sein, globale Ressourcen zu begrenzen. Zu den Ressourcen gehören:

  1. Speicher für Schreibpuffer, Blockcache
  2. Komprimierte E/A-Bandbreite
  3. Thread zur Komprimierung
  4. Festplattenressourcen
  5. Dateilöschrate
    RocksDB ermöglicht es Anwendungen, einen oder mehrere Ressourcencontroller für jeden Ressourcentyp zu erstellen und unterstützt so die Priorisierung zwischen RocksDB-Instanzen, um sicherzustellen, dass Ressourcen den Instanzen Priorität eingeräumt werden, die sie am meisten benötigen.

2. Bei der Verwendung mehrerer Instanzen treten Probleme bei der uneingeschränkten Verwendung von Nicht-Thread-Pool-Threads auf. Zu viele Threads erhöhen die Wahrscheinlichkeit einer CPU-Auslastung, verursachen einen übermäßigen Aufwand für den Kontextwechsel, machen das Debuggen extrem schwierig und erhöhen die E/A-Last. RocksDB verwendet am besten einen Thread-Pool, der die Größe und Ressourcennutzung leicht begrenzen kann.

3. Jeder Shard verfügt nur über lokale Informationen. Wenn die RocksDB-Instanz in einem separaten Prozess ausgeführt wird, stellt die globale Ressourcenverwaltung eine größere Herausforderung dar. Es gibt zwei Bewältigungsstrategien:

  1. Verwenden Sie eine konservative Ressourcenstrategie: Reduzieren Sie beispielsweise die Komprimierungshäufigkeit. Der Nachteil dieser Strategie besteht darin, dass globale Ressourcen möglicherweise nicht vollständig genutzt werden.
  2. Informationen zur Ressourcennutzung werden zwischen Instanzen ausgetauscht und entsprechend angepasst, um die Ressourcennutzung globaler zu optimieren. Dies erfordert mehr Arbeit zur Verbesserung der hostweiten Ressourcenverwaltung in RocksDB

WAL-Verarbeitung

Herkömmliche Datenbanken neigen dazu, bei jedem Schreibvorgang ein Write-Ahead-Protokoll (WAL) zu erzwingen, um die Haltbarkeit sicherzustellen. Und große verteilte Speichersysteme replizieren in der Regel Daten für Leistung und Verfügbarkeit und verfügen über verschiedene Konsistenzgarantien.

Daher ist es hilfreich, Optionen zur Optimierung des WAL-Synchronisierungsverhaltens bereitzustellen, um den Anforderungen verschiedener Anwendungen gerecht zu werden.
Konkret führt RocksDB differenzierte WAL-Betriebsmodi ein: (1) synchrone WAL-Schreibvorgänge, (2) gepufferte WAL-Schreibvorgänge, (3) keine WAL-Schreibvorgänge. Für die gepufferte WAL-Verarbeitung wird WAL regelmäßig mit niedriger Priorität im Hintergrund auf die Festplatte geschrieben, um die Datenverkehrslatenz von RocksDB nicht zu beeinträchtigen

Begrenzen Sie die Geschwindigkeit beim Löschen von Dateien

RocksDB interagiert normalerweise über das Dateisystem mit dem zugrunde liegenden Speichergerät, und das Dateisystem kennt den Flash-Speicher (SSD). Das Löschen von Dateien auf der SSD kann die interne Speicherbereinigung der SSD auslösen, was zu massiven Datenbewegungen führt und sich negativ auf die E/A-Latenz auswirkt.
Es wurde eine Begrenzung der Dateilöschrate eingeführt, um zu verhindern, dass mehrere Dateien gleichzeitig (während der Komprimierung) gelöscht werden.

Datenformat kompatibel

Es ist wichtig, dass die Daten auf der Festplatte zwischen verschiedenen Softwareversionen rückwärts- und vorwärtskompatibel bleiben.

Konfigurationsmanagement

RocksDB ist hochgradig konfigurierbar, sodass Anwendungen für ihre Arbeitslasten optimiert werden können. Allerdings stellt das Konfigurationsmanagement eine Herausforderung dar:
Die frühe Konfiguration wird von LevelD geerbt und eine große Anzahl von Konfigurationen ist mit dem Code gekoppelt. RocksDB hat seine Konfigurationsmethode angepasst und aktualisiert.

Qualitätssicherung

  • F: Warum verwendet MemTable eine Sprungtabelle anstelle eines ausgeglichenen Baums?

  • A: 1. Die Implementierung der Sprungtabelle ist einfacher als die des Baums; 2. Sie nimmt weniger Platz ein, außer den Daten, alles andere ist ein Zeiger; 3. Die Daten sind geordnet, was für Bereichsabfragen praktisch ist .

  • F: Warum verwendet MySQL B+-Bäume ohne Sprungtabellen?

  • A: 1. Die Seiten des B+-Baums entsprechen natürlich den Plattenblöcken, was plattenfreundlicher ist; während die Sprungtabelle auf der Grundlage der verknüpften Liste implementiert wird, ist die physische Verteilung der Daten relativ verstreut, was jedoch nicht der Fall ist Freundlich für E/A; 2. Die Sprungtabelle kann keinen Clustered-Index und
    Coverage-Index implementieren; 3. Die Datenverteilung kann kein Festplatten-Vorlesen nutzen, was nicht freundlich für den Festplatten-Cache ist
    . Kurz gesagt, das Design der Sprungtabelle ist einfach, passt nicht zu den Eigenschaften der Festplatte und ist für die Speichernutzung geeignet.

Referenzdokumente

Ich denke du magst

Origin blog.csdn.net/qq_30708747/article/details/120841257
Empfohlen
Rangfolge