sql >> Database teknologi >  >> NoSQL >> Redis

Introduktion til Redis-datastrukturer:Hashes

Redis-hashes er (intuitivt nok!) hashes, der knytter strengnavne til strengværdier. De er i det væsentlige navngivet containere med unikke felter og deres værdier. De er den perfekte måde at repræsentere et objekt som en Redis-datastruktur. Som forventet giver de konstant tid grundlæggende operationer som get, set, exists osv. En masse avancerede operationer er også tilvejebragt. Den fulde liste over hash-kommandoer er her.

Lad os tage det en tur fra redis-cli .

# 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"

Som vi er blevet til at forvente af vores hosting for Redis™* som en datastrukturserver, ser vi, at Redis leverer ret nyttige og avancerede operationer på hashes.

Internal

Ligesom Redis-sæt er Redis-hash også implementeret som ordbøger. Ordbøger i Redis er implementeret som hashtabeller, der bruger hashfunktionen MurmurHash2 og vokser via trinvis størrelsesændring. Hashkollisioner håndteres ved lænkning. Flere detaljer kan findes i Redis-implementeringen af ​​ordbogen på dict.c.
Som med sæt er der lageroptimering lavet til mindre hashes. Denne datastruktur kaldes ziplist (Hashes blev optimeret ved hjælp af en anden datastruktur kaldet zipmap før Redis 2.6) i Redis-implementeringen. Det er i bund og grund en specielt kodet dobbeltforbundet liste, der er optimeret til hukommelsesbesparelser. Dataene såvel som pointerne er gemt inline. Ziplist bruges også til at optimere opbevaring af mindre sorterede sæt og lister. En hash, når den er fladtrykt ind i en sådan liste, ser noget ud som [nøgle1, værdi1, nøgle2, værdi2, ...]. Hvordan er dette mere effektivt end almindelige nøgler? Hashes med få nøgler kan pakkes smart ind i denne lineære array-lignende struktur (dvs. ziplisten), mens de stadig garanterer amortiseret O(1)-ydelse for get og set. Det kan naturligvis ikke følge med, da hash-felterne øges. Efterhånden som hashen vokser, konverteres den til standardordbogsstrukturen for at opretholde O(1)-ydeevnen, og pladsbesparelsen går tabt. Redis-konfigurationsparametre, der styrer denne transformation, er:

  • list-max-ziplist-entries standard (512):Skift til standardrepræsentation, hvis hash bliver større end denne grænse.
  • list-max-ziplist-value standard (64):Skift til standardrepræsentation, hvis det største element i hashen bliver større end denne grænse.

Flere detaljer kan forstås fra koden og kommentarerne i implementeringen, som findes her. Hukommelsesbesparelserne ved at bruge denne specielle optimering er betydelige. Vi vil tale mere om i det næste afsnit.

Hukommelsesoptimering

En af de velkendte anbefalinger til hukommelsesbesparelser ved brug af Redis er at bruge hashes i stedet for almindelige strenge. Dette er en vigtig use-case til at udnytte kraften i Redis hashes i applikationer i den virkelige verden. Fra den officielle Redis-dokumentation om hukommelsesoptimering:

Brug hashes, når det er muligt

Små hashes er kodet i et meget lille rum, så du bør prøve at repræsentere dine data ved hjælp af hashes, hver gang det er muligt. Hvis du f.eks. har objekter, der repræsenterer brugere i en webapplikation, skal du bruge en enkelt hash med alle de påkrævede felter i stedet for at bruge forskellige nøgler til navn, efternavn, e-mail, adgangskode.

Dette indlæg fortsætter derefter med at foreslå en måde at kortlægge en række objekter i et sæt hashes for at drage fordel af hukommelsesbesparelserne. Instagram beskriver i et meget populært blogindlæg brugen af ​​en lignende teknik, som hjalp dem med at opnå størrelsesordener af potentielle besparelser. En anden blog, der forsøger at måle fordelene ved optimeringen, er denne.

Applikationer

  • Redis Hashes er naturligt velegnet til at gemme objekter:sessioner, brugere, besøgende osv. Dette gør det til en af ​​de vigtigste datastrukturer leveret af Redis.
  • I sin hukommelsesoptimerede form er det et glimrende valg til cachelagring af store mængder data.

Et objektadresselager

Da hukommelsesoptimering er en vigtig case for hashes, lad os diskutere et eksempel svarende til Instagram-implementeringen for at vise, hvordan man bruger hukommelsesbesparende funktioner i Redis hashes. Lad os sige, at vi har en enorm Content-adresserbar lagring (CAS) implementering med hundredvis af millioner af objekter gemt. Hvert objekts placering er en hash-streng. Vi har til hensigt at udvikle et opslagssystem for at finde ud af objektets placering givet dets ID. Den typiske måde at gøre dette på i Redis vil være at bruge en streng.

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

Denne tilgang fungerer fint. Men da antallet af objekter, vi har, er enormt, vil vi ende med at få brug for meget hukommelse til Redis. Vi vil gerne gøre det bedre. Lad os tage den hukommelsesoptimerede hash-tilgang til dette problem. Vi bliver nødt til at vælge de rigtige værdier for list-max-ziplist-entries og list-max-ziplist-value . Den korrekte værdi for list-max-ziplist-value er uanset hvad den maksimale længde af hash-strengen for lageradressen kan være. Værdien af ​​list-max-ziplist-entries skal holdes lavt nok og vil afhænge af antallet af samlede hash buckets vi ønsker at oprette. Det er bedst at finde ud af empirisk. For f.eks. for 100 millioner objekter kunne vi vælge at bruge 100.000 hashes. De maksimale indtastninger i det tilfælde vil være 100m / 100k =1000. Applikationens logik til at bestemme, hvilken hash et objekts lageradresse går ind i, kan være:divider objekt-id'et med 100k og kasser resten. Således vil objekt-id 14590860 gå ind i hash (14590860/100k) =145 dvs.


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

Denne implementering vil ikke bare være meget lettere på hukommelsen, men bør også give god cache-lokalitet.

Her er vores andre indlæg i Redis-datastrukturserien.

  • Redis-sæt
  • Redis bitmaps
  • Gendisponerede sorterede sæt

  1. Mongodb:flere samlinger eller en stor samling med indeks

  2. Fuldtekstsøgning med vægt i mongoose

  3. MongoDB Java Driver-databaseforbindelse pooling med Tomcat

  4. json.loads og Redis i python 3.5