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

Einführung in Redis-Datenstrukturen:Hashes

Redis-Hashes sind (intuitive genug!) Hashes, die Zeichenfolgennamen Zeichenfolgenwerten zuordnen. Sie sind im Wesentlichen benannte Container mit eindeutigen Feldern und ihren Werten. Sie sind die perfekte Möglichkeit, ein Objekt als Redis-Datenstruktur darzustellen. Wie erwartet bieten sie grundlegende Operationen wie get, set,exists usw. in konstanter Zeit. Eine Reihe fortgeschrittener Operationen wird ebenfalls bereitgestellt. Die vollständige Liste der Hash-Befehle finden Sie hier.

Lassen Sie es uns auf der redis-cli ausprobieren .

# hmset key field value [field value ...] :  Insert elements in a hash. O(N), N is # of field being set
127.0.0.1:6379> hmset std:101 name "John Smith" dob "01-01-2000" gender M active 0 cgpa 2.9
OK

# hgetall key : key all keys and values in the hash. O(N), N is size of hash
127.0.0.1:6379> hgetall std:101
 1) "name"
 2) "John Smith"
 3) "dob"
 4) "01-01-2000"
 5) "gender"
 6) "M"
 7) "active"
 8) "0"
 9) "cgpa"
10) "2.9"
127.0.0.1:6379> hmset std:102 name "Jane" name "Ann"
OK
# If duplicates are found, only the last set is valid
127.0.0.1:6379> hgetall std:102
1) "name"
2) "Ann"

# hexists key field: does field exist in the hash with key. O(1)
127.0.0.1:6379> hexists std:102 cgpa
(integer) 0

# hincrby key field increment: Increment the integer field by increment. O(1)
127.0.0.1:6379> hincrby std:101 active 1
(integer) 1

# hget key field : the value for field in the hash stored at key. O(1)
127.0.0.1:6379> hget std:101 active
1) "1"
# If field doesn't exist, hincrby sets it to 0 and then applies increment
127.0.0.1:6379> hincrby std:102 active 2
(integer) 2

# hmget key field [field ...]: the values of the fields requested for the hash with key. O(N), N is # of keys requested
127.0.0.1:6379> hmget std:102 active
1) "2"

# hincrbyfloat key field increment: Increment the float value in field by increment. O(1) 
127.0.0.1:6379> HINCRBYFLOAT std:101 cgpa 1.0
"3.9"

# HSETNX key field value: set field to value if not alread set. O(1)
127.0.0.1:6379> hsetnx std:102 cgpa 4.0
(integer) 1
127.0.0.1:6379> hget std:102 cgpa
"4.0"

# hlen key: number of fields in the hash. O(1)
127.0.0.1:6379> hlen std:101
(integer) 5

# hkeys key : all fields in the hash. O(N), N is size of hash
127.0.0.1:6379> hkeys std:101
1) "name"
2) "dob"
3) "gender"
4) "active"
5) "cgpa"

Wie wir es von unserem Hosting für Redis™* als Datenstrukturserver gewohnt sind, sehen wir, dass Redis ziemlich nützliche und fortgeschrittene Operationen für Hashes bietet.

Interna

Wie Redis-Sätze werden auch Redis-Hashes als Wörterbücher implementiert. Wörterbücher in Redis sind als Hash-Tabellen implementiert, die die Hash-Funktion MurmurHash2 verwenden und durch inkrementelle Größenanpassung wachsen. Hash-Kollisionen werden durch Verkettung behandelt. Weitere Details finden Sie in der Redis-Implementierung des Wörterbuchs auf dict.c.
Wie bei Sets gibt es eine Speicheroptimierung für kleinere Hashes. Diese Datenstruktur wird in der Redis-Implementierung Ziplist genannt (Hashes wurden mit einer anderen Datenstruktur namens Zipmap vor Redis 2.6 optimiert). Es handelt sich im Wesentlichen um eine speziell codierte doppelt verknüpfte Liste, die für Speichereinsparungen optimiert ist. Die Daten sowie die Zeiger werden inline gespeichert. Ziplist wird auch verwendet, um die Speicherung kleinerer sortierter Sätze und Listen zu optimieren. Ein Hash, wenn er in eine solche Liste abgeflacht wird, sieht etwa so aus:[Schlüssel1, Wert1, Schlüssel2, Wert2, ...]. Wie ist das effizienter als einfache Tasten? Hashes mit wenigen Schlüsseln können geschickt in diese lineare Array-ähnliche Struktur (d. h. die Ziplist) gepackt werden, während immer noch amortisierte O(1)-Leistung für Get und Set garantiert wird. Offensichtlich kann dies nicht mithalten, wenn die Hash-Felder zunehmen. Wenn der Hash wächst, wird er in die Standardverzeichnisstruktur konvertiert, um die Leistung von O(1) aufrechtzuerhalten, und die Platzersparnis geht verloren. Redis-Konfigurationsparameter, die diese Umwandlung steuern, sind:

  • list-max-ziplist-entrys Standard (512):Wechsel zur Standarddarstellung, wenn der Hash größer als diese Grenze wird.
  • list-max-ziplist-value Standard (64):Wechsel zur Standarddarstellung, wenn das größte Element im Hash größer als diese Grenze wird.

Weitere Details können aus dem Code und den Kommentaren in der hier zu findenden Implementierung verstanden werden. Die Speichereinsparungen durch die Verwendung dieser speziellen Optimierung sind erheblich. Wir werden im nächsten Abschnitt ausführlicher darauf eingehen.

Speicheroptimierung

Eine der bekannten Empfehlungen zur Speichereinsparung bei der Verwendung von Redis ist die Verwendung von Hashes anstelle von einfachen Zeichenfolgen. Dies ist ein wichtiger Anwendungsfall, um die Leistungsfähigkeit von Redis-Hashes in realen Anwendungen zu nutzen. Aus der offiziellen Redis-Dokumentation zur Speicheroptimierung:

Verwenden Sie nach Möglichkeit Hashes

Kleine Hashes werden auf sehr kleinem Raum codiert, daher sollten Sie versuchen, Ihre Daten so oft wie möglich mit Hashes darzustellen. Wenn Sie beispielsweise Objekte haben, die Benutzer in einer Webanwendung darstellen, verwenden Sie statt unterschiedlicher Schlüssel für Name, Nachname, E-Mail und Passwort einen einzigen Hash mit allen erforderlichen Feldern.

Dieser Beitrag schlägt dann eine Möglichkeit vor, eine Reihe von Objekten einem Satz von Hashes zuzuordnen, um die Speichereinsparungen zu nutzen. Instagram beschreibt in einem sehr beliebten Blogbeitrag die Verwendung einer ähnlichen Technik, die ihnen geholfen hat, Größenordnungen an potenziellen Einsparungen zu erzielen. Ein weiterer Blog, der versucht, die Vorteile der Optimierung zu messen, ist dieser.

Anwendungen

  • Redis-Hashes eignen sich natürlich zum Speichern von Objekten:Sitzungen, Benutzer, Besucher usw. Dies macht sie zu einer der wichtigsten Datenstrukturen, die von Redis bereitgestellt werden.
  • In seiner speicheroptimierten Form ist es eine ausgezeichnete Wahl für das Caching großer Datenmengen.

Ein Objektadressspeicher

Da die Speicheroptimierung ein wichtiger Anwendungsfall für Hashes ist, lassen Sie uns ein Beispiel ähnlich der Instagram-Bereitstellung diskutieren, um zu zeigen, wie Speichersparfunktionen von Redis-Hashes genutzt werden können. Nehmen wir an, wir haben eine riesige Bereitstellung von Content Addressable Storage (CAS) mit Hunderten Millionen von gespeicherten Objekten. Der Standort jedes Objekts ist eine Hash-Zeichenfolge. Wir beabsichtigen, ein Nachschlagesystem zu entwickeln, um den Standort des Objekts anhand seiner ID herauszufinden. Der typische Weg, dies in Redis zu tun, ist die Verwendung einer Zeichenfolge.

set object:14590860 "007f80f0a62408..."
set object:11678 "009f80abcd0a60..."
...

Dieser Ansatz funktioniert einwandfrei. Da die Anzahl der Objekte, die wir haben, jedoch riesig ist, benötigen wir am Ende viel Speicher für Redis. Wir wollen es besser machen. Nehmen wir den speicheroptimierten Hash-Ansatz für dieses Problem. Wir müssen die richtigen Werte für list-max-ziplist-entries auswählen und list-max-ziplist-value . Der richtige Wert für list-max-ziplist-value ist, was auch immer die maximale Länge der Hash-Zeichenfolge der Speicheradresse sein kann. Der Wert von list-max-ziplist-entries muss niedrig genug gehalten werden und hängt von der Anzahl der gesamten Hash-Buckets ab, die wir erstellen möchten. Das lässt sich am besten empirisch ermitteln. Für z.B. für 100 Millionen Objekte könnten wir 100.000 Hashes verwenden. Die maximalen Einträge betragen in diesem Fall 100m / 100k =1000. Die Logik der Anwendung, um zu entscheiden, in welchen Hash die Speicheradresse eines Objekts gelangt, kann folgendermaßen aussehen:Teilen Sie die Objekt-ID durch 100k und verwerfen Sie den Rest. Somit wird die Objekt-ID 14590860 in den Hash (14590860/100k) =145 umgewandelt, d. h.


hset object:145 14590860 "007f80f0a62408..."
hget object:145 14590860
> "007f80f0a62408..."

Diese Implementierung ist nicht nur viel speichersparender, sondern sollte auch eine gute Cache-Lokalität bieten.

Hier sind unsere anderen Posts in der Redis-Datenstrukturreihe.

  • Redis-Sets
  • Redis-Bitmaps
  • Sortierte Sätze redis