Pourquoi Redis si vite - angle de stockage de données

L'esprit de cet article est la suivante:

I. Introduction et application

Redis est un écrit en ANSI langage C, d'excellentes performances, réseau de soutien, la persistance base de données mémoire K-K, et fournit des API multi-langues. Il est de type essentiellement commun String, Liste, Hash, Set, Zset ces cinq

Redis dans les entreprises Internet ont généralement les applications suivantes:

  • Chaîne: mise en cache, ce qui limite, compteurs, verrouillage distribué, Session distribuée
  • Hash: informations utilisateur magasin, visites à domicile de l'utilisateur, les requêtes combinées
  • Liste: personnes concernent microblogging listes de chronologie, Simple Queue
  • Set: louange, piétiner, étiquettes, amitié
  • Zset: Leaderboard

Un autre exemple est le fournisseur d'électricité au moment d'une grande promotion, utilisera une conception spéciale pour assurer la stabilité du système, l'inventaire peut déduire la conception suivante considérer:

La figure ci-dessus, l'inventaire Redis de déduction directe, après l'enregistrement par travailleur synchronisé à la base de données, dans la conception de la nécessité d'envisager la synchronisation des travailleurs de traitement simultané et traitement répétitif.

On peut voir Redis est très efficace et stable, et que le Redis sous-jacente est de savoir comment atteindre grâce à l'application du scénario ci-dessus?

Deux, objet Redis redisObject

Lorsque nous exécutons un monde jeu de commandes bonjour, aura le modèle de données suivantes:

  • dictEntry: Redis-valeur de clé de chaque attribué une clé dictEntry, qui touche avec le pointeur et val, les points de la liste suivante à l'autre dictEntry formés, le pointeur peut être une pluralité de valeurs de hachage pour la même clé sont reliés entre eux, donc à résoudre le problème des collisions de hachage (méthode d'adresse de chaîne).
  • sds: Touche « bonjour » est un SDS (chaînes simples dynamiques) stockées en détail plus loin.
  • redisObject: valeur redisObject val « monde » est stocké. En effet, Redis 5 types courants sont stockés dans redisObject et redisObject le champ de type valeur indique le type de l'objet, champ d'adresse ptr pointe sur un objet est situé.

objet redisObject est très important, le type d'objet Redis, code interne, la récupération de la mémoire, les objets partagés et d'autres fonctions, le soutien nécessaire de redisObject. Les avantages de cette conception est que, pour différents scénarios d'utilisation peuvent, du type utilisé de façon classique 5 fourni pour obtenir une variété de différentes structures de données, permet d'optimiser l'efficacité de l'objet selon différents scénarios.

Si l'objet dictEntry ou redisObject, objets SDS nécessite de la mémoire d'allocation (par exemple, que jemalloc) l'allocation de mémoire pour le stockage. jemalloc Redis comme l'allocateur de mémoire par défaut, pour réduire la fragmentation de la mémoire fait meilleure. exemple jemalloc, système 64 bits, l'espace de mémoire est divisé en petites, grandes, vaste gamme de trois, chaque intervalle est divisé de nombreux petits blocs d'unités de mémoire; Redis lors du stockage de données, sélectionne le plus la taille appropriée du bloc de mémoire pour le stockage.

Comme mentionné ci-dessus, la Redis redisObject chaque objet est représenté par une structure dont le pointeur ptr à la structure de données de l'application sous-jacente, la structure de données est déterminée par l'attribut de codage. Par exemple, nous exécutons les commandes suivantes pour obtenir magasin « bonjour » code correspondant:

Redis tous les types de structure de données comme suit (important, sera utilisé plus tard):

Trois, cordes

objet String qui sous-tend la mise en uvre peut être int, cru, embstr (correspondant au nom de la table description ci-dessus). embstr de codage est d'allouer un espace continu en appelant une fonction d'allocation de mémoire, et le besoin brut appeler deux fois.

int codé chaîne codée embstr objet chaîne et l'objet sous certaines conditions, être converties en objet chaîne codée brut. embstr: < = 39 chaîne d'octets. int: 8 octets entier. brut: supérieure à 39 chaîne d'octets.

Simple Dynamic String (SDS), cette structure est comme C ++ ou Java Chaîne de ArrayList < caractère > Longueur variable dynamiquement:

sdshdr struct { Longueur // buf dans l'espace occupé int len; // la longueur de l'espace libre restant dans buf int libre; // espace de données carbonisation buf ; // '\ 0' null terminaison };
  • obtenir: sdsrange --- O (n)
  • set: sdscpy-O (n)
  • créer: sdsnew --- O (1)
  • len: sdslen --- O (1)

Obtenir longueur chaîne de complexité constante: que la longueur fiche len propriétés de SDS, de façon à obtenir une longueur de SDS complexité en temps est O (1).

allocation pré-espace: Si vous apportez des modifications à un SDS, est divisé en de deux situations:

  • longueur SDS (valeur len) est inférieure à 1 Mo, le programme attribuera la même taille et les propriétés len espace inutilisé, la valeur de la même propriété et len libre. Par exemple, le SDS deviendront len octets 15, le programme sera affecté 15 octets de l'espace non utilisé, la longueur réelle du réseau buf devient SDS 15 + 15 + 1 = 31 octets (un octet supplémentaire Les utilisateurs gagnent caractère espace).
  • longueur SDS (valeur len) de pas moins que 1MB, les ayants droit de programme de l'espace inutilisé de 1MB. Par exemple, après modification, SDS devient len de 30MB, sa longueur réelle est 30MB + 1 Mo + 1 byte.

Inerte espace libre: Après avoir effectué sdstrim (chaîne prise), SDS ne libère pas immédiatement l'espace supplémentaire, si la prochaine opération de raccordement de chaîne, l'épissage et pas grand espace vient de sortir, l'espace inutilisé qui volonté Dollars au travail. espace libre par un gaz inerte évite certains cas manipuler des chaînes d'opération de redistribution de la mémoire.

Pour éviter tout débordement de la mémoire tampon: lors de l'utilisation procédure chaîne de C, si la longueur de chaîne est augmentée (par exemple strcat fonctionnement) et d'oublier la mémoire réattribue, est susceptible de mémoire tampon de motif déborde, car la longueur d'enregistrement du SDS, l'opération correspondante peut entraîner il va réallouer automatiquement débordement de mémoire tampon, afin d'éviter le débordement de tampon.

Quatre, Liste

Liste objet est réalisé sous-jacente Pense-bête (liste rapide, la liste est une combinaison de compression et ZipList liste chaînée amphidrome chaînée). Redis liste de soutien d'insertion et d'éjection des deux extrémités, et l'élément peut être obtenu pour indiquer l'emplacement (ou la plage), il peut agir comme un tableau, la file d'attente, pile, et analogues.

typedef struct {ListNode // noeud devant struct ListNode * prev; // noeud arrière struct ListNode * suivant; // valeur de nud * valeur nulle; } ListNode; Liste des typedef struct { // noeud d'en-tête * ListNode tête; // nud de pied de page ListNode * queue; // valeur noeud fonction de copie void * (* dup) (void * ptr); // fonction de libération de valeur de nud void (* libre) (void * ptr); // fonction de comparaison de valeur de nud int (* jeu) (void * ptr, clé void *); // nombre de noeuds inclus dans la liste unsigned long len; } Liste;
  • rpush: listAddNodeHead --- O (1)
  • lpush: listAddNodeTail --- O (1)
  • pression: listInsertNode --- O (1)
  • index: LISTINDEX --- O (N)
  • pop: ListFirst / listLast --- O (1)
  • llen: listLength --- O (N)

4,1 chaînée (chaîne double-face)

Cette structure est plus comme le Java LinkedList, sont intéressés peuvent lire le code source.

Comme on peut le voir sur la figure les Redis LinkedList liste à double extrémité présente les caractéristiques suivantes: des noeuds avec prev, pointeur suivant, le pointeur de tête et du pointeur de queue, avant l'accès de noeud, la complexité arrière du noeud, les noeuds d'en-tête et de pied sont des nuds il est O (1). propriété len obtient le nombre de noeuds est O (1).

Par rapport aux deux extrémités liste chaînée, la liste peut être compressé pour économiser l'espace mémoire, mais des modifications ou des suppressions d'exploitation, la complexité élevée, ainsi que le nombre de noeuds, la liste peut être utilisée compression, mais le nombre de nuds est grande, ou l'utilisation de la liste amphidrome rentable.

4.2 ZipList (Liste d'emballage)

Lorsqu'une liste de clé contient seulement une petite liste des articles et est un petit entier ou une chaîne de longueur relativement courte, Redis puis sur l'utilisation ZipList (liste de compression) pour faire la liste des clés implémentation sous-jacente.

Pour économiser de la mémoire Redis ZipList est développé, est un bloc continu de mémoire un ensemble particulier de codage (plutôt que sous forme de liste à deux extrémités de chaque noeud est un pointeur vers) une structure de données constituée de type séquentiel, la structure spécifique est relativement compliqué, lecteur intéressé vous pouvez voir le modèle de mémoire d'analyse structurale Redis de hachage. liste liste quicklist utilisation dans la nouvelle version remplace la ZipList et chaînée:

Listes rapides ZipList et est un mélange de chaînée. Il chaînée par section de segmentation, chaque section ZipList utilisé pour stocker compact, connecté en série entre une pluralité de pointeurs bidirectionnels ZipList. Étant donné que la liste de l'espace supplémentaire est relativement élevé, et le pointeur suivant PREV représentera 16 octets (pointeur de système 64 bits est de 8 octets), chaque noeud supplémentaire est la mémoire allouée séparément, la fragmentation de la mémoire va exacerber , une incidence sur l'efficacité de la gestion de la mémoire.

profondeur de compression par défaut quicklist est 0, qui ne sont pas compressés. Pour soutenir les opérations push / pop rapide, tout compris de deux quicklist ZipList non comprimé, la profondeur est 1. Pour plus d'économiser de l'espace, Redis aussi au stockage ZipList comprimé, l'utilisation algorithme de compression LZF.

Cinq, Hash

la mise en uvre sous-jacente de l'objet Hash peut être ZipList (emballage Liste) ou Hashtable (également appelé dictionnaire ou d'une table de hachage).

objet de hachage seulement si les deux conditions suivantes seront utilisées ZipList (liste de compression): 1 inférieur au nombre d'éléments dans la table de hachage 512, 2 touches et la longueur de la chaîne de valeurs de hachage de toutes les clés sont à moins de 64 octets.

tables de hachage Hashtable peut être atteint O (1) la complexité des opérations de lecture et d'écriture, et par conséquent, une grande efficacité. Source comme suit:

typedef struct {dict // fonctions spécifiques de type dictType * de type; // données privées void * privdata; // table de hachage dictht ht ; // resucée Index // resucée lorsqu'ils ne sont pas en cours, une valeur de -1 int rehashidx; / * ressasser pas en cours si rehashidx == -1 * / // nombre actuel de sécurité iterator fonctionnement int itérateurs; / * nombre de itérateurs en cours d'exécution * / } Dict; typedef struct {dictht // tableau de table de hachage dictEntry tableau **; // taille de la table de hachage taille unsigned long; // taille de la table de masque de hachage pour calculer une valeur d'index // taille toujours égale - 1 sizemask unsigned long; // Le nombre de table de hachage d'un nud existant unsigned long utilisé; } Dictht; typedef struct {dictEntry vide clé *; union {void * val; uint64_t U64; int64_t S64;} v; // pointe vers la prochaine table de hachage du noeud, une liste liée est formée struct dictEntry * suivant; } DictEntry; typedef struct {dictType // fonction pour calculer une valeur de hachage unsigned int (* fonction de hachage) (const clé void *); // touches de fonction de copie void * (* keyDup) (void * privdata, clé const void *); // fonction des valeurs de copie void * (* valDup) (void * privdata, const void * obj); // touches de fonction de comparaison int (* keyCompare) (void * privdata, const void * key1, const void * key2); // clé destructor void (* keyDestructor) (void * privdata, clé void *); // valeur destructor void (* valDestructor) (void * privdata, void * obj); } DictType;

La structure source ci-dessus peut être simplifiée comme suit:

Cette structure est similaire à la précédente JDK7 HashMap < String, Object > Quand il y a deux clés sont attribués ou plus au même tableau d'index de hachage est généré une collision de hachage. Redis également utiliser la loi pour résoudre les conflits clés d'adresse de la chaîne. -À-dire, chaque noeud possède une table de hachage de pointeur suivante, une table de hachage pluralité de noeuds constituant un ensemble unique avec le pointeur suivant, la méthode d'adresse de liaison est d'organiser les objets dans la même valeur de hachage dans une liste de hachage correspondant à la valeur de la fente.

Redis Hashtable utilisé comme le dictionnaire, puis la mise en uvre sous-jacente, chaque dictionnaire sera avec deux tables de hachage, un habituellement utilisé, une autre utilisation (resucée) que ressasser. Avec l'opération de la table de hachage, la clé sera progressivement augmentée ou diminuée. Afin de permettre le coefficient d'occupation de la table de hachage est maintenue dans des limites raisonnables, la taille de la table de hachage Redis va se dilater ou se contracter (réchauffé), qui est, ht [0] dont toutes les paires de valeurs de clé dans multiple, progressive la mouture à ht [1] à l'intérieur.

Six, Set

Définir collection sous-jacente d'objets peut être atteint IntSet (entiers) ou Hashtable (également appelé dictionnaire ou d'une table de hachage).

IntSet (entiers) Quand un ensemble ne contenant que des nombres entiers, et l'élément utilise un peu IntSet (entiers) que la collection d'objets sous-jacents mis en uvre ensemble.

typedef struct {IntSet // encodage codant pour uint32_t; // nombre d'éléments contenus dans la collection longueur uint32_t; // élément Enregistrer du tableau int8_t contenu ; } IntSet;
  • sadd: intsetAdd --- O (1)
  • smembers: intsetGetO (1) --- O (N)
  • srem: intsetRemove --- O (N)
  • slen: intsetlen --- O (1)

IntSet mise en uvre sous-jacente a ordonné, répétée sans tenir le tableau des éléments de collection. Tapez IntSet cette structure peut être d'un tableau d'entiers à 16 bits, 32 bits, 64 bits. Si le tableau sont tous entiers longueur 16 bits, si le nouvel ajout d'un entier de 32 bits, l'ensemble du réseau 16 sera mis à niveau vers un réseau de 32 bits. La mise à niveau peut améliorer IntSet de flexibilité, mais peut aussi économiser de la mémoire, mais irréversible.

7.ZSet

Zset ensemble ordonné d'objets sous-jacents peuvent être atteints ZipList (liste compressé) ou skiplist (table de saut).

Quand un nombre relativement important d'éléments ou des membres de l'ensemble ordonné est une chaîne de caractères relativement longue, Redis sur l'utilisation skiplist (table de saut) mis en uvre comme Zset objet sous-jacent.

typedef struct {zskiplist // noeud en-tête et une table de noeud queue struct zskiplistNode * en-tête, queue *; // le nombre de noeuds dans le tableau unsigned long length; // nombre maximal de couches dans la table du numéro de noeud de couches niveau int; } Zskiplist; typedef struct {zskiplistNode // objets membres robj * obj; // partition double Score; // Retour pointeur struct zskiplistNode * vers l'arrière; // couche struct zskiplistLevel { // pointeur vers l'avant struct zskiplistNode * vers l'avant; // --- durée à partir du noeud au pointeur de noeud courant est dirigé vers l'avant durée unsigned int; } Niveau ; } ZskiplistNode;

Zadd Moyenne --- --- zslinsert O (logN), le pire O (N)

Moyenne zrem --- --- zsldelete O (logN), le pire O (N)

zrank - zslGetRank --- moyenne O (logN), le pire O (N)

Trouvez skiplist complexité temporelle est LogN, et peut être tout à fait équilibré arbre binaire, mais dépasse simple à mettre en uvre. table de saut (skiplist) est une structure de données ordonnée qui est maintenue par une pluralité de liens vers d'autres noeuds dans un pointeur de noeud, de manière à atteindre noeud d'accès rapide.

Origi Wijnaldum double, Liverpool 4-0 total de points 4-3 inverse Barcelone
Précédent
"Boom", 51 ans, a dit un jour qu'être acteur est trop triste, mais n'a heureusement pas joué le rôle de Batman
Prochain
Pékin police de la circulation enquête approfondie des vélos électriques sur la route sans permis ne dispose pas d'une peine de suspension de licence de 20 yuans
Technologie Dieu répond | iqiyi les mises à pied nient, ne demandez pas, demandez est d'optimiser
Lac Qinghai dans le gibier d'eau se réunissent oiseaux aquatiques d'élevage plus de trois mille
IntelliJ IDEA de l'entrée dans le tutoriel addictif
Ne pas besoin de beauté, ils ont le plus beau visage
3000000000 comment envoyer des enveloppes rouges pour vous dire comment attraper SAIC Chase
Excel4J excle Kit
Demi-pension: Ao Liji arrêté pour briser Ali chanson dépanneuse, Liverpool 1-0 Barcelone
chanteur, âgé de 29 ans cancer Li Wei a échoué, la défiguration et sans voix, franchement espère juste que je peux vivre jusqu'à Juillet
Hainan dans le moratoire de la pêche mer de Chine méridionale période 17,496 bateaux de pêche dans le port
Les gens ne regardent la caméra! Les visiteurs ont été ouverts 10 jours Hanada a été « blessé »
ressort à base de démarrage / nuage de printemps de projets d'infrastructure udf