sql >> Databáze >  >> NoSQL >> Redis

Úvod do datových struktur Redis:hash

Haše Redis jsou (dostatečně intuitivně!) haše, které mapují názvy řetězců na hodnoty řetězců. Jsou to v podstatě pojmenované kontejnery jedinečných polí a jejich hodnot. Jsou dokonalým způsobem, jak reprezentovat objekt jako datovou strukturu Redis. Podle očekávání poskytují základní operace v konstantním čase, jako je get, set, exists atd. K dispozici je také spousta pokročilých operací. Úplný seznam hash příkazů je zde.

Podívejme se na to z 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"

Jak jsme od našeho hostingu pro Redis™* jako server datové struktury očekávali, vidíme, že Redis poskytuje poměrně užitečné a pokročilé operace s hodnotami hash.

Interní informace

Stejně jako sady Redis jsou i hash Redis implementovány jako  slovníky. Slovníky v Redis jsou implementovány jako hashovací tabulky, které používají hashovací funkci MurmurHash2 a rostou pomocí přírůstkové změny velikosti. Hašovací kolize jsou řešeny řetězením. Další podrobnosti lze nalézt v implementaci slovníku Redis na adrese dict.c.
Stejně jako u sad je optimalizace úložiště vytvořena pro menší hashe. Tato datová struktura se v implementaci Redis nazývá ziplist (Haše byly optimalizovány pomocí jiné datové struktury nazývané zipmap před Redis 2.6). Je to v podstatě speciálně kódovaný dvojitě propojený seznam, který je optimalizován pro úsporu paměti. Data, stejně jako ukazatele, jsou uloženy inline. Ziplist se také používá k optimalizaci ukládání menších setříděných sad a seznamů. Hash, když je sloučen do takového seznamu, vypadá něco jako [klíč1, hodnota1, klíč2, hodnota2, ...]. Jak je to efektivnější než obyčejné klíče? Hashe s několika klíči lze chytře zabalit do této struktury podobné lineárnímu poli (tj. ziplistu), a přitom stále zaručovat amortizovaný výkon O(1) pro get and set. Je zřejmé, že to nemůže držet krok, protože hash pole přibývají. Jak hash roste, převádí se do standardní struktury slovníku, aby se zachoval výkon O(1) a dochází ke ztrátě úspory místa. Konfigurační parametry Redis řídící tuto transformaci jsou:

  • list-max-ziplist-entries default (512):Změňte na standardní reprezentaci, pokud hash překročí tento limit.
  • seznam-max-hodnota-ziplist default (64):Změňte na standardní reprezentaci, pokud největší prvek v hash překročí tento limit.

Další podrobnosti lze pochopit z kódu a komentářů v implementaci, které najdete zde. Úspora paměti při použití této speciální optimalizace je značná. Budeme o tom hovořit podrobněji v další části.

Optimalizace paměti

Jedním z dobře známých doporučení pro úsporu paměti při používání Redis je použití hash namísto prostých řetězců. Toto je důležitý případ použití pro využití síly hashů Redis v aplikacích v reálném světě. Z oficiální dokumentace Redis o optimalizaci paměti:

Pokud je to možné, používejte hash

Malé hashe jsou zakódovány na velmi malém prostoru, takže byste se měli pokusit reprezentovat svá data pomocí hash pokaždé, když je to možné. Máte-li například objekty představující uživatele ve webové aplikaci, místo použití různých klíčů pro jméno, příjmení, e-mail, heslo použijte jeden hash se všemi povinnými poli.

Tento příspěvek pak pokračuje návrhem jednoho způsobu, jak namapovat řadu objektů do sady hashů a využít tak úspory paměti. Instagram ve velmi oblíbeném příspěvku na blogu popisuje použití podobné techniky, která jim pomohla dosáhnout řádových potenciálních úspor. Další blog, který se pokouší změřit přínosy optimalizace, je tento.

Aplikace

  • Hash Redis jsou přirozeně vhodné k ukládání objektů:relací, uživatelů, návštěvníků atd. Díky tomu je jednou z klíčových datových struktur poskytovaných Redisem.
  • Ve své podobě optimalizované pro paměť je vynikající volbou pro ukládání velkého množství dat do mezipaměti.

Úložiště adres objektů

Vzhledem k tomu, že optimalizace paměti je důležitým případem použití hashů, pojďme diskutovat o příkladu podobném nasazení Instagramu, abychom ukázali, jak využít funkce pro úsporu paměti hashů Redis. Řekněme, že máme obrovské nasazení pro úložiště s adresným obsahem (CAS) se stovkami milionů uložených objektů. Umístění každého objektu je hash řetězec. Máme v úmyslu vyvinout vyhledávací systém pro zjištění polohy objektu na základě jeho ID. Typickým způsobem, jak toho dosáhnout v Redis, je použít řetězec.

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

Tento přístup funguje dobře. Protože však počet objektů, které máme, je obrovský, nakonec budeme pro Redis potřebovat hodně paměti. Chceme to dělat lépe. Podívejme se na tento problém pomocí hashovacího přístupu optimalizovaného pro paměť. Budeme muset vybrat správné hodnoty pro list-max-ziplist-entries a list-max-ziplist-value . Správná hodnota pro list-max-ziplist-value je jakákoli maximální délka hash řetězce adresy úložiště. Hodnota list-max-ziplist-entries musí být udržována dostatečně nízká a bude záviset na počtu celkových hash bucketů, které chceme vytvořit. Nejlépe se to zjistí empiricky. Pro např. pro 100 milionů objektů jsme si mohli vybrat použití 100 000 hashů. Maximální hodnoty v tomto případě budou 100 m / 100 k =1 000. Logika aplikace při rozhodování, do kterého hash adresa úložiště objektu půjde, může být:vydělit ID objektu 100 k a zbytek zahodit. Objekt ID 14590860 tedy přejde do hash (14590860/100k) =145, tj.


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

Tato implementace bude nejen mnohem lehčí na paměť, ale měla by také poskytovat dobré umístění mezipaměti.

Zde jsou naše další příspěvky v řadě datových struktur Redis.

  • Sady Redis
  • Bitmapy Redis
  • Seřazené sady Redis

  1. Redis Stack Exchange, jak odstranit nebo získat klíče podle vzoru

  2. Jak sdělit klientovi, kde nový master Redis používá Sentinel

  3. MongoDB $ max

  4. Jak Hadoop funguje – Pochopte fungování Hadoopu