Ich möchte eine JSON-Nutzlast in Redis speichern. Es gibt wirklich zwei Möglichkeiten, wie ich das tun kann:
Eine mit einfachen String-Schlüsseln und Werten.
Schlüssel: Benutzer, Wert: Nutzlast (der gesamte JSON-Blob, der 100-200 KB groß sein kann)SET user:1 payload
Hashes verwenden
HSET user:1 username "someone"
HSET user:1 location "NY"
HSET user:1 bio "STRING WITH OVER 100 lines"
Denken Sie daran, dass die Wertelänge nicht vorhersehbar ist, wenn ich einen Hash verwende. Sie sind nicht alle kurz wie das obige Bio-Beispiel.
Was ist speichereffizienter? Verwenden Sie Zeichenfolgenschlüssel und -werte oder einen Hash?
Antworten:
Dies hängt davon ab, wie Sie auf die Daten zugreifen:
Wählen Sie Option 1:
Wählen Sie Option 2:
PS: Wählen Sie als Faustregel die Option, für die in den meisten Anwendungsfällen weniger Abfragen erforderlich sind.
quelle
JSON
Nutzlast erwartet wird (ein klassisches Problem der nichtatomarenread-modify-write
).Dieser Artikel bietet hier viele Einblicke: http://redis.io/topics/memory-optimization
Es gibt viele Möglichkeiten, ein Array von Objekten in Redis zu speichern ( Spoiler : Ich mag Option 1 für die meisten Anwendungsfälle):
Speichern Sie das gesamte Objekt als JSON-codierte Zeichenfolge in einem einzigen Schlüssel und verfolgen Sie alle Objekte mithilfe eines Satzes (oder einer Liste, falls zutreffend). Beispielsweise:
Im Allgemeinen ist dies in den meisten Fällen wahrscheinlich die beste Methode. Wenn das Objekt viele Felder enthält, Ihre Objekte nicht mit anderen Objekten verschachtelt sind und Sie in der Regel nur auf eine kleine Teilmenge von Feldern gleichzeitig zugreifen, ist es möglicherweise besser, Option 2 zu wählen.
Vorteile : gilt als "gute Praxis". Jedes Objekt ist ein ausgewachsener Redis-Schlüssel. Die JSON-Analyse ist schnell, insbesondere wenn Sie auf viele Felder für dieses Objekt gleichzeitig zugreifen müssen. Nachteile : langsamer, wenn Sie nur auf ein einzelnes Feld zugreifen müssen.
Speichern Sie die Eigenschaften jedes Objekts in einem Redis-Hash.
Vorteile : gilt als "gute Praxis". Jedes Objekt ist ein ausgewachsener Redis-Schlüssel. JSON-Zeichenfolgen müssen nicht analysiert werden. Nachteile : Möglicherweise langsamer, wenn Sie auf alle / die meisten Felder in einem Objekt zugreifen müssen. Außerdem können verschachtelte Objekte (Objekte innerhalb von Objekten) nicht einfach gespeichert werden.
Speichern Sie jedes Objekt als JSON-Zeichenfolge in einem Redis-Hash.
Auf diese Weise können Sie ein wenig konsolidieren und statt vieler Schlüssel nur zwei Schlüssel verwenden. Der offensichtliche Nachteil ist, dass Sie die TTL (und andere Dinge) nicht für jedes Benutzerobjekt festlegen können, da es sich lediglich um ein Feld im Redis-Hash und nicht um einen vollständigen Redis-Schlüssel handelt.
Vorteile : Die JSON-Analyse ist schnell, insbesondere wenn Sie auf viele Felder für dieses Objekt gleichzeitig zugreifen müssen. Weniger "Verschmutzung" des Hauptschlüssel-Namespace. Nachteile : Ungefähr die gleiche Speichernutzung wie bei Nummer 1, wenn Sie viele Objekte haben. Langsamer als # 2, wenn Sie nur auf ein einzelnes Feld zugreifen müssen. Wahrscheinlich nicht als "gute Praxis" angesehen.
Speichern Sie jede Eigenschaft jedes Objekts in einem dedizierten Schlüssel.
Gemäß dem obigen Artikel wird diese Option fast nie bevorzugt (es sei denn, die Eigenschaft des Objekts muss eine bestimmte TTL oder etwas anderes haben).
Vorteile : Objekteigenschaften sind vollständige Redis-Schlüssel, die für Ihre App möglicherweise nicht übertrieben sind. Nachteile : Langsam, verbraucht mehr Speicher und wird nicht als "Best Practice" angesehen. Viel Verschmutzung des Hauptschlüssel-Namespace.
Gesamtübersicht
Option 4 wird im Allgemeinen nicht bevorzugt. Die Optionen 1 und 2 sind sehr ähnlich und beide sind ziemlich häufig. Ich bevorzuge Option 1 (im Allgemeinen), da Sie damit kompliziertere Objekte (mit mehreren Verschachtelungsebenen usw.) speichern können. Option 3 wird verwendet, wenn Sie wirklich daran interessiert sind, den Hauptschlüssel-Namespace nicht zu verschmutzen (dh Sie möchten dort nicht viele Schlüssel in Ihrer Datenbank zu sein und Sie interessieren sich nicht für Dinge wie TTL, Key Sharding oder was auch immer).
Wenn ich hier etwas falsch gemacht habe, hinterlasse bitte einen Kommentar und erlaube mir, die Antwort vor dem Downvoting zu überarbeiten. Vielen Dank! :) :)
quelle
obj
und speichern Felder wie Ansichten, Stimmen und Wähler mit separaten Schlüsseln. Auf diese Weise erhalten Sie mit einer einzigen READ-Abfrage das gesamte Objekt und können dennoch dynamische Teile Ihres Objekts schnell aktualisieren? Die relativ seltenen Aktualisierungen von Feldern in der JSON-Zeichenfolge können durch Lesen und Zurückschreiben des gesamten Objekts in einer Transaktion erfolgen.Einige Ergänzungen zu einer Reihe von Antworten:
Wenn Sie Redis-Hash effizient nutzen möchten, müssen Sie zunächst die maximale Anzahl der Schlüssel und die maximale Größe der Schlüssel kennen. Andernfalls konvertiert Redis den Hash-Max-Ziplist-Wert oder die Hash-Max-Ziplist-Einträge praktisch in übliche Schlüssel / Wert-Paare unter einer Haube. (siehe Hash-Max-Ziplist-Wert, Hash-Max-Ziplist-Einträge) Und das Unterbrechen einer Hash-Option unter einer Haube ist WIRKLICH SCHLECHT, da jedes übliche Schlüssel / Wert-Paar in Redis +90 Bytes pro Paar verwendet.
Dies bedeutet, dass Sie, wenn Sie mit Option 2 beginnen und versehentlich aus dem Max-Hash-Ziplist-Wert ausbrechen, +90 Bytes pro JEDEM ATTRIBUT erhalten, das Sie im Benutzermodell haben! (eigentlich nicht die +90 aber +70 siehe Konsolenausgabe unten)
Für die Antwort von TheHippo sind Kommentare zu Option 1 irreführend:
hgetall / hmset / hmget zur Rettung, wenn Sie alle Felder oder mehrere get / set-Operationen benötigen.
Für BMiner Antwort.
Die dritte Option macht wirklich Spaß. Für einen Datensatz mit max (id) <has-max-ziplist-value weist diese Lösung eine O (N) -Komplexität auf, da Reddis überraschenderweise kleine Hashes als Array-ähnlichen Container mit Länge / Schlüssel / Wert speichert Objekte!
Aber Sie sollten sich keine Sorgen machen, Sie werden Hash-Max-Ziplist-Einträge sehr schnell brechen und los geht's, Sie sind jetzt tatsächlich bei Lösung Nummer 1.
Die zweite Option wird höchstwahrscheinlich unter einer Haube zur vierten Lösung führen, da die Frage lautet:
Und wie Sie bereits sagten: Die vierte Lösung ist mit Sicherheit das teuerste +70 Byte pro Attribut.
Mein Vorschlag, wie man einen solchen Datensatz optimiert:
Sie haben zwei Möglichkeiten:
Wenn Sie die maximale Größe einiger Benutzerattribute nicht garantieren können, entscheiden Sie sich für die erste Lösung, und wenn der Speicher wichtig ist, komprimieren Sie den Benutzer json, bevor Sie ihn in redis speichern.
Wenn Sie die maximale Größe aller Attribute erzwingen können. Dann können Sie Hash-Max-Ziplist-Einträge / Wert festlegen und Hashes entweder als einen Hash pro Benutzerdarstellung oder als Hash-Speicheroptimierung aus diesem Thema eines Redis-Handbuchs verwenden: https://redis.io/topics/memory-optimization und Benutzer als JSON-Zeichenfolge speichern. In beiden Fällen können Sie auch lange Benutzerattribute komprimieren.
quelle