Apache Cassandra. Datenaufzeichnung. Teil 2 – Memtable


Cassandra_logoIch präsentiere Ihnen den zweiten Artikel in einer Reihe, die sich mit dem Schreiben von Daten in das Cassandra DBMS befasst. Dieses Mal möchte ich Informationen über die nächste Komponente bereitstellen – den Zwischendaten-Cache von Spaltenfamilien..

Unmittelbar nach dem Einfügen der Daten in das Festschreibungsprotokoll werden die Informationen auch in eine Struktur namens Memtable dupliziert. Diese Komponente hat die folgenden Eigenschaften:

  • Die in Memtable gespeicherten Elemente werden nach Aufzeichnungsschlüsseln sortiert.
  • Die Daten in den Datensätzen sind nach Spalten sortiert.
  • Zum Suchen und Einfügen von Elementen wird der Algorithmus verwendet Java ConcurrentSkipListMap;;
  • Für jede Spaltenfamilie gibt es eine separate MemTable (im Englischen wird Memtable als beschrieben per-ColumnFamily-Struktur ).

Schauen wir uns jetzt alles genauer an. Um die Struktur von Memtable besser zu verstehen, ergänzen wir die Abbildungen aus dem ersten Teil der Überprüfung (Apache Cassandra. Datenprotokollierung. Teil 1 – Festschreibungsprotokoll). Ich möchte Sie daran erinnern, dass die Bilder in Anlehnung an Abbildungen aus der offiziellen Dokumentation erstellt wurden. .

Commit-Protokoll-MemtableSo funktioniert es: Der Prozess der Datenaufzeichnung beginnt mit der Protokollierung aller Vorgänge im Festschreibungsprotokoll. Dies ist für die Wiederherstellung bei einem Knotenausfall erforderlich. Unmittelbar danach werden die Daten in der Memtable dupliziert. Memtable protokolliert jedoch nicht die genaue Speicherung aller Vorgänge im Allgemeinen, sondern speichert nur die neuesten Daten. Dies ist unter dem Gesichtspunkt ziemlich logisch, dass RAM-Speicher viel teurer ist als Festplattenspeicher. Aufgrund der Tatsache, dass die Daten in Memtable nach dem Datensatzschlüssel und innerhalb des Schlüssels nach Spalten sortiert sind, kann unsere Abbildung entsprechend kompliziert sein. Nehmen wir eine erweiterte Version des Schemas auch aus dem vorherigen Teil der Übersicht über den Datenaufzeichnungsprozess:

Commit-Protokoll-Memtable erweitert

Eine kleine Klarstellung ist erforderlich – da es für jede Spaltenfamilie eine separate Memtable-Datenstruktur gibt, bedeutet die CF-Kennzeichnung Spaltenfamilie. Innerhalb jeder CF werden die Daten nach dem Schreibschlüssel sortiert. Spaltendaten sind Nutzdaten, die als Spalten dargestellt werden. Die unterschiedlichen Längen der Datensegmente sind darauf zurückzuführen, dass die Anzahl und das Volumen der Spalten in einem Datensatz selbst innerhalb derselben Spaltenfamilie erheblich variieren können. Ich habe dieses architektonische Merkmal im Artikel von Apache Cassandra ausführlich beschrieben. Primärschlüssel und Funktionen zum Speichern von Datensätzen.

Der Algorithmus “Liste überspringen” wird verwendet, um neue Elemente zu finden und in Memtable einzufügen. oder vielmehr seine Implementierung in Java – ConcurrentSkipListMap … Zu verstehen, wie es funktioniert, ist im Zusammenhang mit dem Erlernen von Memtable nicht unbedingt erforderlich. Dieser Algorithmus beschleunigt jedoch die bereits schnelle Suche im RAM noch weiter. Daher werde ich kurz versuchen, die Grundlagen zu erläutern.

Das Prinzip des Algorithmus besteht darin, mehrere Ebenen mit Daten zu erstellen. Die erste Ebene enthält eine Liste aller Schlüssel in aufsteigender Reihenfolge. Mit einer bestimmten Wahrscheinlichkeit kann jeder Wert von der ersten Ebene auf die zweite Ebene dupliziert werden. Die Werte aus der zweiten Ebene können mit einiger Wahrscheinlichkeit auch auf eine höhere Ebene dupliziert werden, und so weiter. Lücken sind nicht zulässig. Beispielsweise können Sie auf der ersten und dritten Ebene keinen Wert haben und nicht auf der zweiten. Bei der Suche nach Elementen geht der Appell zuerst auf die höchste Ebene, der erste gefundene Wert wird mit dem gewünschten verglichen, und wenn er nicht gleich ist, gehen wir auf die darunter liegende Ebene und je nachdem, ob der aktuelle Wert von dem gewünschten ist weniger oder mehr, die Suche geht in Richtung abnehmender bzw. zunehmender Elemente … Dieser Vorgang wird am besten durch die Animation (zum Anzeigen klicken) aus dem Artikel auf Wikipedia gezeigt ::

Skip_list_add_element

Sie können sich den Algorithmus Schritt für Schritt im Artikel über Habré genauer ansehen und einige andere Quellen und wir gehen weiter.

Auf die Daten in Memtable kann anschließend von Client-Leseanforderungen als Cache zugegriffen werden. Dies ist auch einer der Unterschiede zum Festschreibungsprotokoll, an das keine Clientanforderungen gestellt werden können.

Wenn die Memtable eine bestimmte Größe erreicht, werden die Daten in eine Struktur namens SSTable geleert, die sich auf der Festplatte befindet. Mit dem Parameter können Sie die maximale Memtable-Größe anpassen memtable_total_space_in_mb, Dies ist die Standardeinstellung seit Cassandra Version 2.0.2 wurde gleich einem Viertel (zuvor ein Drittel) der für die Größe des Java-Heapspeichers zugewiesenen Speichermenge.

Der Java-Speicher wird wiederum von Cassandra unabhängig verwaltet und abhängig von der RAM-Größe werden die folgenden Werte festgelegt ::

RAM Wurfgröße
Weniger als 2 GB 1/2 RAM
Von 2 GB bis 4 GB 1 GB
Mehr als 4 GB 1/4 RAM, aber nicht mehr als 8 GB

Es wird nicht empfohlen, ein Volumen von mehr als 8 GB bereitzustellen, da die Kosten für Wartungsaufgaben auf ein kritisches Niveau ansteigen (z. B. Speicherbereinigung) und die Möglichkeit besteht, die Prozesse des Betriebssystems zu beeinflussen:

Viele Benutzer, die Cassandra noch nicht kennen, sind versucht, die Größe des Java-Heapspeichers zu hoch einzustellen, was den größten Teil des Arbeitsspeichers des zugrunde liegenden Systems beansprucht. In den meisten Fällen ist das Erhöhen der Java-Heap-Größe aus folgenden Gründen tatsächlich nachteilig:

– In den meisten Fällen nimmt die Fähigkeit von Java, die Speicherbereinigung über 8 GB ordnungsgemäß zu handhaben, schnell ab.

– Moderne Betriebssysteme verwalten den Seiten-Cache des Betriebssystems für Daten, auf die häufig zugegriffen wird, und halten diese Daten sehr gut im Speicher, können jedoch durch eine erhöhte Java-Heap-Größe daran gehindert werden, ihre Aufgabe zu erfüllen.

Wenn Sie über mehr als 2 GB Systemspeicher verfügen, was typisch ist, halten Sie die Größe des Java-Heaps relativ klein, um mehr Speicher für den Seitencache zu ermöglichen.

Der nächste Parameter, der für den Betrieb von Memtable verantwortlich ist – file_cache_size_in_mb… Gemessen an der Beschreibung in der offiziellen Dokumentation wird es als Zwischencache zum Lesen von Daten (SSTable-Lesepuffer) verwendet, bevor diese in SSTable geschrieben werden.

Sie können Memtable mithilfe der Parameter flexibel steuern memtable_flush_writers und memtable_flush_queue_size … Der erste Parameter gibt die Anzahl (standardmäßig von 2 bis 8) der Instanzen des Prozesses an, die für das Löschen von Daten auf die Festplatte verantwortlich sind. Wenn Sie über viele Datenverzeichnisse, einen großen Java-Heap oder viele Festplatten verfügen, um Daten von Memtable auf die Festplatte zu verschieben, wird empfohlen, diesen Wert zu erhöhen und damit den Prozess zu parallelisieren. Dies gilt auch bei Verwendung einer SSD. Der zweite Parameter legt die maximale Anzahl der vollständigen Memtable fest, die darauf warten, auf die Festplatte gespült zu werden. Es wird empfohlen, einen Wert festzulegen, der der maximalen Anzahl von Indizes einer Spaltenfamilie entspricht. Diese Empfehlung bezieht sich auf die Besonderheit des Speicherns von Indizes: Ein Index für eine Spaltenfamilie ist tatsächlich eine andere Spaltenfamilie, deren Schlüssel das Indexfeld der ursprünglichen CF ist ::

Auf der Speicherebene ist ein Sekundärindex einfach eine andere Spaltenfamilie, wobei der Schlüssel der Wert der indizierten Spalte ist und die Spalten die Zeilenschlüssel der indizierten Tabelle enthalten.

… Cassandra findet Indexeinträge zusammen mit den zugehörigen ursprünglichen Tabellenschlüsseln.

Es lohnt sich, die in Cassandra 2.1 eingeführten Änderungen in Bezug auf Memtable gesondert zu betrachten. … Wenn sich Memtable vor dieser Version ausschließlich im Java-Heap befand, können Sie den Memtable-Puffer jetzt in den eigenen Speicher von Cassandra verschieben. In diesem Zusammenhang wurden die entsprechenden Variablen zu den Konfigurationsparametern hinzugefügt. Parameter memtable_allocation_type definiert drei neue Werte (ich überspringe den ersten, da er dem Speichertyp vor 2.1 entspricht) ::

– offheap_buffers verschiebt die Zelle Name und Wert für DirectBuffer-Objekte. Dies hat die geringste Auswirkung auf Lesevorgänge – die Werte sind immer noch “Live” -Java-Puffer -, reduziert jedoch den Heap nur erheblich, wenn Sie große Zeichenfolgen oder Blobs speichern.

– offheap_objects verschiebt die gesamte Zelle vom Heap und lässt nur übrig die NativeCell-Referenz enthält einen Zeiger auf die nativen (Off-Heap-) Daten. Dies macht es auch für kleine Werte wie Ints oder UUIDs effektiv, auf Kosten des vorübergehenden Kopierens auf den Heap beim Lesen.

Für mich bleiben die Fragen relevant für das, was DirectBuffer verantwortlich ist und wie es funktioniert, denn zuerst heißt es: „Bewegt das Zelle Name und Wert zu DirectBuffer “und dann” die Werte sind immer noch “lebende” Java-Puffer. Auf Stackoverflow habe ich die Antwort bekommen diesbezüglich:

Ein DirectBuffer ist ein Speicherbereich, der direkt mit JNA zugewiesen wird (wahrscheinlich mit malloc). Er darf keine “lebenden” Java-Objekte enthalten. Sie müssen serialisiert werden. Dieser Speicher wird jedoch nicht von der JVM verwaltet und daher von GC ignoriert.

Die Parameter memtable_heap_space_in_mb stehen in direktem Zusammenhang mit dem Cache-Typ Memtable и memtable_offheap_space_in_mb , die für die Größe des Puffers für die On-Heap- bzw. Off-Heap-Zuordnung verantwortlich sind.

Der letzte neue Parameter ist memtable_cleanup_threshold … Gibt das Verhältnis der belegten nicht zurücksetzbaren Memtable-Größe zur zulässigen Gesamtgröße an. Ein hoher Wert bedeutet häufiges Speichern von Daten in kleinen SSTables.


Einige Quellen enthalten etwas veraltete Informationen zu memtable. Im Folgenden sind einige Überlegungen aufgeführt, die für Besitzer früherer Versionen von Cassandra relevant sein können. Sie sollten jedoch nicht alles auf Glauben setzen. In vielen Fällen sind dies nur meine eigenen Gedanken.

Es ist bekannt, dass für eine Spaltenfamilie mehrere Memtable-Dateien vorhanden sein können – eine ist aktuell, der Rest muss noch auf die Festplatte geschrieben werden. ::

Es können mehrere Memtabellen für eine einzelne Spaltenfamilie vorhanden sein, wobei ein Strom und der Rest darauf warten, geleert zu werden.

Es bleibt jedoch die Frage, was “vollständige memtable” bedeutet und warum empfohlen wird, den Wert des Parameters memtable_flush_queue_size auf die maximale Anzahl von Indizes für eine Spaltenfamilie festzulegen ::

Die Anzahl der vollständigen Memtables, die ein ausstehendes Flush ermöglichen sollen (Memtables warten auf einen Schreibthread). Stellen Sie mindestens die maximale Anzahl von Indizes ein, die für eine einzelne Tabelle erstellt wurden.

Möglicherweise findet der folgende Algorithmus statt: Wenn ein einzelnes Festschreibungsprotokollsegment seine maximale Größe erreicht, wird eine neue Festschreibungsprotokolldatei (eine für alle CFs) auf der Festplatte erstellt und neue Memtables (eine für jede CF) werden im RAM erstellt. Gleichzeitig wird das alte Festschreibungsprotokoll mit Bit 0 markiert (dh es wartet auf eine Spüloperation). Wenn eine der maximalen Grenzen erreicht ist – commitlog_total_space_in_mb für Commit-Protokoll und memtable_total_space_in_mb für memtable -, wird die älteste vollständige memtable in die Warteschlange gestellt (memtable-Flush-Warteschlange) und nach dem Leeren auf die Festplatte in SSTable gelöscht (genau wie das entsprechende Commit) Protokolle). Dies ist nur meine Vermutung basierend auf den Informationen, die ich im Internet finden konnte.

Kommentare bereitgestellt von HyperComments

Leave a Reply

Your email address will not be published. Required fields are marked *