20 votes

Utilisation de la mémoire HSET vs SET ?

Je lisais cet article qui mentionne que le stockage de 1Million de clés dans redis utilisera 17GB de mémoire. Cependant, lorsque l'on passe à des hachages en les découpant à 1k chacun (ex : HSET "mediabucket:1155" "1155315" "939" ) leur permet de stocker 1M dans 5GB, ce qui représente une économie assez importante.

Je lis optimisation de la mémoire de redis mais je ne comprends pas bien la différence. Il est dit que les HGETs ne sont pas tout à fait O(1) mais suffisamment proches et il est mentionné que l'utilisation du processeur est plus importante lorsque l'on utilise des hsets. Je ne comprends pas pourquoi il y aurait une plus grande utilisation du processeur (c'est sûr, on échange du temps contre de l'espace, mais comment/quoi ?) Il est fait mention d'un "encodage" mais pas de la manière dont il est encodé.

Il mentionne également la mention "only string", mais je n'ai aucune idée de ce que signifie "only string". S'agit-il du champ de hachage ? Cela signifie-t-il le champ de hachage ? Je ne vois rien à ce sujet dans HSET . Qu'est-ce qui serait codé exactement et pourquoi le codage serait-il plus efficace que l'utilisation d'un SET ?

Comment est-il possible HSET "mediabucket:1155" "1155315" "939" est plus efficace que SET "mediabucket:1155315" "939" ? Il y a moins de données dans SET (1155315 et 1155 est utilisé plutôt que 1155315). Personnellement, j'essaierais d'utiliser des clés binaires, mais je ne pense pas que cela ait un rapport avec la raison pour laquelle les HSET sont plus efficaces.

EDIT :

Publication croisée sur la liste de diffusion redis-db également : https://groups.google.com/d/topic/redis-db/90K3UqciAx0/discussion

22voto

Didier Spezia Points 23333

Les petits objets de hachage sont encodés sous forme de ziplists en fonction des valeurs des paramètres hash-max-ziplist-entries et hash-max-ziplist-value. Il s'agit d'une sérialisation simple des données.

Une ziplist est définie comme suit (extrait du code source de Redis) :

/* The ziplist is a specially encoded dually linked list that is designed
* to be very memory efficient. It stores both strings and integer values,
* where integers are encoded as actual integers instead of a series of
* characters. It allows push and pop operations on either side of the list
* in O(1) time. However, because every operation requires a reallocation of
* the memory used by the ziplist, the actual complexity is related to the
* amount of memory used by the ziplist.
*
* ----------------------------------------------------------------------------
*
* ZIPLIST OVERALL LAYOUT:
* The general layout of the ziplist is as follows:
* <zlbytes><zltail><zllen><entry><entry><zlend>
*
* <zlbytes> is an unsigned integer to hold the number of bytes that the
* ziplist occupies. This value needs to be stored to be able to resize the
* entire structure without the need to traverse it first.
*
* <zltail> is the offset to the last entry in the list. This allows a pop
* operation on the far side of the list without the need for full traversal.
*
* <zllen> is the number of entries.When this value is larger than 2**16-2,
* we need to traverse the entire list to know how many items it holds.
*
* <zlend> is a single byte special value, equal to 255, which indicates the
* end of the list.
*
* ZIPLIST ENTRIES:
* Every entry in the ziplist is prefixed by a header that contains two pieces
* of information. First, the length of the previous entry is stored to be
* able to traverse the list from back to front. Second, the encoding with an
* optional string length of the entry itself is stored.
*
* The length of the previous entry is encoded in the following way:
* If this length is smaller than 254 bytes, it will only consume a single
* byte that takes the length as value. When the length is greater than or
* equal to 254, it will consume 5 bytes. The first byte is set to 254 to
* indicate a larger value is following. The remaining 4 bytes take the
* length of the previous entry as value.
*
* The other header field of the entry itself depends on the contents of the
* entry. When the entry is a string, the first 2 bits of this header will hold
* the type of encoding used to store the length of the string, followed by the
* actual length of the string. When the entry is an integer the first 2 bits
* are both set to 1. The following 2 bits are used to specify what kind of
* integer will be stored after this header. An overview of the different
* types and encodings is as follows:
*
* |00pppppp| - 1 byte
*      String value with length less than or equal to 63 bytes (6 bits).
* |01pppppp|qqqqqqqq| - 2 bytes
*      String value with length less than or equal to 16383 bytes (14 bits).
* |10______|qqqqqqqq|rrrrrrrr|ssssssss|tttttttt| - 5 bytes
*      String value with length greater than or equal to 16384 bytes.
* |11000000| - 1 byte
*      Integer encoded as int16_t (2 bytes).
* |11010000| - 1 byte
*      Integer encoded as int32_t (4 bytes).
* |11100000| - 1 byte
*      Integer encoded as int64_t (8 bytes).
* |11110000| - 1 byte
*      Integer encoded as 24 bit signed (3 bytes).
* |11111110| - 1 byte
*      Integer encoded as 8 bit signed (1 byte).
* |1111xxxx| - (with xxxx between 0000 and 1101) immediate 4 bit integer.
*      Unsigned integer from 0 to 12. The encoded value is actually from
*      1 to 13 because 0000 and 1111 can not be used, so 1 should be
*      subtracted from the encoded 4 bit value to obtain the right value.
* |11111111| - End of ziplist.
*
* All the integers are represented in little endian byte order.
*/

Chaque élément de l'objet de hachage est représenté comme un couple clé/valeur dans la ziplist (2 entrées successives). La clé et les valeurs peuvent être stockées sous la forme d'une simple chaîne de caractères ou d'un nombre entier. Ce format est plus compact en mémoire car il permet d'économiser beaucoup de pointeurs (8 octets chacun) qui sont nécessaires pour implémenter une structure de données dynamique (comme une vraie table de hachage).

L'inconvénient est que les opérations HSET/HGET sont en fait O(N) lorsqu'elles sont appliquées à la ziplist. C'est pourquoi la ziplist doit rester petite. Lorsque les données de la ziplist tiennent dans le cache L1 du CPU, les algorithmes correspondants sont assez rapides malgré leur complexité linéaire.

Vous pouvez vous référer aux liens suivants pour plus d'informations :

Redis utilise 10 fois plus de mémoire que de données

Espace requis pour la structure de données Redis

Ces réponses font référence à d'autres structures de données (comme les ensembles, les listes ou les ensembles triés), mais il s'agit exactement du même concept.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X