Redis
 sql >> Datenbank >  >> NoSQL >> Redis

Redis 10x mehr Speicherverbrauch als Daten

Nun, das wird von jeder effizienten Datenspeicherung erwartet:Die Wörter müssen im Speicher in einer dynamischen Datenstruktur von Zellen indiziert werden, die durch Zeiger verbunden sind. Größe der Strukturmetadaten, Zeiger und interne Fragmentierung des Speicherzuordners ist der Grund, warum die Daten viel mehr Speicher beanspruchen als eine entsprechende flache Datei.

Ein Redis-Set wird als Hash-Tabelle implementiert. Dazu gehören:

  • ein Array von Zeigern, die geometrisch wachsen (Potenzen von zwei)
  • Ein zweites Array kann erforderlich sein, wenn inkrementelles Rehashing aktiv ist
  • einfach verknüpfte Listenzellen, die die Einträge in der Hash-Tabelle darstellen (3 Zeiger, 24 Bytes pro Eintrag)
  • Redis-Objekt-Wrapper (einer pro Wert) (16 Byte pro Eintrag)
  • tatsächliche Daten selbst (jeweils mit vorangestelltem 8 Byte für Größe und Kapazität)

Alle oben genannten Größen gelten für die 64-Bit-Implementierung. Unter Berücksichtigung des Speicherzuweisungs-Overheads führt dies dazu, dass Redis mindestens 64 Bytes pro Satzelement (zusätzlich zu den Daten) für eine neuere Version von Redis benötigt, die die Jemalloc-Zuweisung verwendet (>=2.4)

Redis bietet Speicheroptimierungen für einige Datentypen, aber sie decken keine Sätze von Zeichenfolgen ab. Wenn Sie den Speicherverbrauch von Sets wirklich optimieren müssen, gibt es jedoch Tricks, die Sie anwenden können. Ich würde dies nicht für nur 160 MB RAM tun, aber sollten Sie größere Datenmengen haben, können Sie Folgendes tun.

Wenn Sie die Vereinigungs-, Schnittmengen- und Differenzfähigkeiten von Mengen nicht benötigen, können Sie Ihre Wörter in Hash-Objekten speichern. Der Vorteil ist, dass Hash-Objekte automatisch von Redis mit Zipmap optimiert werden können, wenn sie klein genug sind. Der Zipmap-Mechanismus wurde in Redis>=2.6 durch Ziplist ersetzt, aber die Idee ist dieselbe:Verwendung einer serialisierten Datenstruktur, die in die CPU-Caches passt, um sowohl Leistung als auch einen kompakten Speicherbedarf zu erzielen.

Um sicherzustellen, dass die Hash-Objekte klein genug sind, könnten die Daten gemäß einem Hash-Mechanismus verteilt werden. Angenommen, Sie müssen 1 Million Elemente speichern, könnte das Hinzufügen eines Wortes folgendermaßen implementiert werden:

  • Hash es modulo 10000 (wird auf der Client-Seite ausgeführt)
  • HMSET-Wörter:[Hashnum] [Wort] 1

Statt zu speichern:

words => set{ hi, hello, greetings, howdy, bonjour, salut, ... }

Sie können speichern:

words:H1 => map{ hi:1, greetings:1, bonjour:1, ... }
words:H2 => map{ hello:1, howdy:1, salut:1, ... }
...

Um die Existenz eines Wortes abzurufen oder zu überprüfen, ist es dasselbe (Hashen Sie es und verwenden Sie HGET oder HEXISTS).

Mit dieser Strategie kann erheblich Speicher eingespart werden, vorausgesetzt, dass das Modulo des Hashs gemäß der Zipmap-Konfiguration gewählt wird (oder Ziplist für Redis>=2.6):

# Hashes are encoded in a special way (much more memory efficient) when they
# have at max a given number of elements, and the biggest element does not
# exceed a given threshold. You can configure this limits with the following
# configuration directives.
hash-max-zipmap-entries 512
hash-max-zipmap-value 64

Achtung:Die Namen dieser Parameter haben sich mit Redis>=2.6 geändert.

Hier bedeutet Modulo 10000 für 1 Million Elemente 100 Elemente pro Hash-Objekt, was garantiert, dass alle als Zipmaps/Ziplists gespeichert werden.