Resumo dos pontos de conhecimento do Redis - estrutura de dados

Este artigo não é um artigo de ensino, é apenas para uma visão geral rápida dos pontos de conhecimento

prefácio

O tipo de superfície e o tipo de fundo do Redis

Para melhorar o desempenho de leitura e gravação, no caso de diferentes tipos e volumes de dados, diferentes métodos de armazenamento e gerenciamento precisam ser usados. Para melhorar a taxa de transferência do servidor, garantindo a facilidade de uso do redis. redis distingue a relação entre a estrutura de dados subjacente e o objeto redis . Por exemplo: quando a quantidade de dados HashMap é pequena, a camada inferior é armazenada na estrutura ziplist em vez de dict; quando o conjunto é uma coleção de inteiros puros, use intset em vez de dict e assim por diante . Aqui, a estrutura de dados e os objetos de superfície da implementação subjacente são resumidos separadamente e, finalmente, o relacionamento entre eles é resolvido. Para esclarecer o princípio de implementação do tipo de dados redis, é muito importante garantir a eficiência de execução dos códigos que envolvem a interação redis no desenvolvimento diário.

meta de aprendizado

  1. Compreender as estruturas de dados de diferentes objetos e seus cenários de uso
  2. Entenda o tempo e a eficiência das conversões entre diferentes estruturas de dados
  3. Entenda que estruturas de dados diferentes funcionam de maneira diferente
  4. Entenda o mecanismo de reciclagem de dados do redis e seu possível impacto

estrutura de dados subjacente

Cadeias Dinâmicas - SDS

característica

  1. A essência é um array dinâmico de caracteres
  2. Caracteres nulos '\0'não são contados em bytes usados ​​nem em bytes não usados
  3. Adote pré-alocação de espaço + estratégia de liberação preguiçosa
  4. Quando o tamanho modificado for menor que 1 MB, o espaço pré-alocado é igual ao espaço usado; quando for maior que 1 MB, o espaço pré-alocado é 1 MB
  5. Liberação preguiçosa significa não liberar ativamente, mas existem APIs sds que fornecem liberação de memória
  6. Segurança binária. '\0'Marque o final da string não com , mas com len
  7. Na implementação, além de existir de forma independente, o SDS também será aninhado em outros tipos em objetos Redis para realizar objetos Redis específicos (por exemplo, dict usa sds para armazenar valores de elementos específicos e implementar mapa de hash)
  1. Estouro de memória: uso de espaço não alocado
  2. Vazamento de memória: o espaço alocado não é mais usado, mas não é liberado
  3. A solicitação de espaço de memória é uma operação lenta: há alternância entre o modo de usuário e o modo kernel e o agendamento de recursos externos (troca de pilha e troca; aplicativo de memória, etc. A velocidade de agendamento de memória é muito mais lenta do que a velocidade de computação da CPU)
  4. Pode ser para melhorar ainda mais a utilização da memória redis. A partir do redis 3.2, a estrutura sdshdr original é dividida em sdshdr5; sdshdr8; sdshdr16; sdshdr32; sdshdr64 para armazenar strings de diferentes comprimentos. Entre eles, o sdshdr5 diz em seu código-fonte que nunca será usado

eficácia

  1. A aquisição do comprimento da string é O(1) —— leia diretamente a variável membro da estrutura sds
  2. A limpeza de strings (sdsclear) é O(1) - realizada diretamente len = 0, sem redefinir valores de elementos individuais
  3. Liberar o espaço de memória (sdsfree) é O(n)—n é o espaço de memória alocado. Observe que é diferente de sdsclear
  1. redis/src/sds.h
  2. redis/src/sds.c

Lista duplamente encadeada - list&listNode

característica

  1. Polimorfismo : listNode usa void *valores armazenados. Diferentes tipos de dup; match; freemétodos listSet<Xxx>Methoddefinidos
  2. A estrutura da lista contém comprimento e ponteiros de cabeça e cauda

eficácia

  1. As operações relacionadas ao predecessor e sucessor são O(1) - obter predecessor/sucessor, inserir nó, excluir determinado nó
  2. As operações que precisam encontrar um único nó são todas O(n) — obter nós por valor, obter nós por índice, excluir nós, etc.
  1. redis/src/adlist.h
  2. redis/src/adlist.c

Pular lista - zskipList&zskipListNode

característica

  1. A estrutura contém diretamente os ponteiros de cabeça e cauda, ​​comprimento e número máximo de camadas
  2. Cada nó contém 1 ponteiro de volta
  3. Cada nó gera ponteiros de avanço de alcance [1, 32] com base na lei de potência
  4. Os membros do nó são classificados por pontuação
  5. Cada objeto membro do nó é único

eficácia

  1. redis/src/servidor.h
  2. redis/src/t_zset.c

Home——dick&dictt&dictEntry

característica

  1. Algoritmo de hash usando murmursh2/3 . Depois de calcular o valor de hash, &sizemaskdetermine a localização do par chave-valor.
  2. Resolver conflitos usando lista encadeada individualmente
  3. Quando o fator de carga for maior que 1 ou 0,5 (gatilho RDB), ele se expandirá e repetirá, e quando for menor que 0,1, reduzirá o espaço e repetirá
  4. O dict armazena dois ponteiros de tabela de hash dicttht[0] e dicttht[1] em uma matriz, que são usados ​​para executar rehash em escala de cinza
  5. Durante o processo de rehash, o dictht[0] de dados antigo apenas diminui, mas não aumenta , e o processo de migração específico é dividido em cada processo CRUD. Contar o progresso atual do rehash por r ehashidx
  6. Durante o rehash, a operação RUD acessará duas tabelas sucessivamente

eficácia

  1. Excluir um par chave-valor específico (Excluir) é O(1), liberar todos os pares chave-valor é O(n)
  2. As operações CRUD são O(1)
  3. O retorno aleatório de pares chave-valor também é O(1)
  1. redis/src/dict.h
  2. redis/src/dict.c
  3. Família de funções MurmurHash e conjunto de testes usados ​​por redis: aappleby/smhasher

Lista comprimida - zipList

característica

  1. é um espaço de armazenamento contínuo
  2. armazenar o deslocamento do nó final
  3. Os primeiros 4 bytes registram o número total de bytes ocupados por toda a ziplist
  4. Marque o final do zipList com 0xFF

para cada nó

  1. Os primeiros 1 ou 5 bytes registram o comprimento do byte do predecessor
  2. Quando o precursor tem menos de 254 bytes, o primeiro byte do nó atual armazena o comprimento do precursor. Caso contrário, o primeiro byte é 0xFE e o comprimento do precursor é registrado nos 4 bytes seguintes

eficácia

  1. As operações relacionadas ao predecessor/sucessor são O(1)
    - calcule a posição do predecessor/sucessor com base no deslocamento
  2. Obtendo o número total de bytes ocupados por zipList é O(1)
    —— armazenado nos primeiros 4 bytes de zipList
  3. O melhor caso para obter o número total de nós em zipList é O(1), e o pior caso é O(n)
    —— o número de nós é maior que 65535
  4. Melhor caso O(n) para pesquisa - número inteiro, pior caso O(n^2) - matriz de bytes
  5. O melhor caso para inserir, criar, excluir é O(n), o pior caso é O(n^2)
    - pode acionar atualizações encadeadas

Conjunto inteiro - intset

característica

  1. Armazene diretamente em uma tabela linear, possivelmente int16[], int32[], int64[]
  2. Quando um novo inteiro exceder o intervalo representado pelo tipo atual, uma operação de atualização será acionada. Novos elementos estarão apenas na cabeça (muito pequena) ou na cauda (muito grande)
  3. Não há operação de downgrade (observe que é diferente da implementação do dict, quando o fator de carga do dict for menor que 0,1, a contração e o rehash serão acionados)

eficácia

  1. Adicionar ou remover novos elementos é O(n)
  2. O processo de busca de uma matriz inteira pode ser pesquisado ao meio, O(log n)
  3. Obter o número de bytes e o número de elementos é O(1), que é diferente de zipList

objeto de superfície

O artigo anterior apresentou a principal estrutura de dados do Redis, mas na implementação específica. Para String, List, Set, ZSet e HashMap são na verdade objetos Redis. Redis define a estrutura RedisObject, que contém um void *ptrusado para apontar para uma estrutura de dados específica. Sob diferentes condições, o mesmo objeto também pode ser armazenado e gerenciado com diferentes estruturas de dados (ou seja, as variáveis ​​de membro ptr do mesmo RedisObject apontam para diferentes estruturas de dados). A seguir, uma breve visão geral dos diferentes RedisObjects.
Definição de RedisObject:

typedef struct redisObject {
    
    
    unsigned type:4;
    unsigned encoding:4;
    unsigned lru:LRU_BITS;
    int refcount;
    void *ptr;
} robj;

Corda

doença método de armazenamento
<= 32Bytes embStr
> 32Bytes SDS
Inteiro, pode ser representado por longo int(longo)
  1. Números de ponto flutuante também são armazenados com embStr ou SDS
  2. INCRBYFLOATAs operações no tipo int acionarão a conversão de tipo

O chamado embStr é usar um espaço de armazenamento contínuo para armazenar estruturas redisObject e SDS ao mesmo tempo. A principal diferença com o SDS é: o SDS precisa executar duas solicitações de memória, enquanto o embStr precisa apenas de um .

Lista

doença método de armazenamento
O comprimento de todos os elementos < list-max-ziplist-value(Byte)
&&
o número de elementos < list-max-ziplist-entries(Byte)
zipList
outro listaligada

Definir

doença método de armazenamento
Todos os elementos podem ser representados por long int
&&
número de elementos < set-max-intset-entries(Byte)
intset
outro ditado

ZSet

doença método de armazenamento
Comprimento de todos os elementos < zset-max-ziplist-value
&&
número de elementos < zset-max-ziplist-entries (Byte)
zipList
outro skipList + dict

Quando houver uma grande quantidade de dados, use duas estruturas diferentes skipList e dict para armazenar os mesmos dados. É benéfico manter a eficiência da busca em O(1), enquanto ordena operações relacionadas (ZRANGE, ZRANK) mantenha O(n)

HashMap

doença método de armazenamento
Comprimento de todos os elementos < zset-max-ziplist-value
&&
número de elementos < zset-max-ziplist-entries (Byte)
zipList
outro ditado
  1. Em zipList, a chave também é um elemento de zipList, e o elemento onde a chave está localizada e o elemento onde o valor está localizado estão sempre próximos
  2. Tanto a chave quanto o valor são armazenados como StringObject. Para obter as características de armazenamento de StringObject, consulte a descrição do objeto String neste artigo.

polimorfismo

O polimorfismo do Redis é implementado com base na verificação de tipo e na verificação do método de codificação. Permite que o mesmo comando execute operações correspondentes em diferentes objetos Redis e métodos de codificação

  1. O Redis usa a verificação de tipo para determinar se um comando pode ser executado para uma chave especificada.
    Por exemplo, DELpode ser executado para todos os tipos, mas GETapenas para String
  2. encodingO Redis avalia como executar uma operação específica em um objeto Redis verificando o método de codificação (como um objeto HashMap, cuja estrutura contém encodingvariáveis ​​de membro, indicando zipListsedict

recuperação de memória

O GC do Redis é basicamente o mesmo que a ideia central do GC do PHP:

  1. Adicionar variáveis refcount​​de membro
  2. O novo objeto tem uma contagem de referência de 1
  3. Adicionado +1 para beber, não mais -1 para ser usado
  4. Solte imediatamente quando 0

A função de reciclagem refere-se ao método de redis/src/object.cdecrRefCount

Mas, além disso, o Redis também gerencia os objetos do Redis por meio do LRU. Você pode ver que a estrutura RedisObject definida acima é unsigned lru:LRU_BITS;usada para registrar o último horário de acesso. Quando a memória usada pelo Redis atinge maxmemory. O lru menor (quanto mais tempo não for usado) será lançado primeiro.

Isso nos lembra que, para evitar a perda de dados, além de garantir o funcionamento normal do nível de hardware do servidor Redis, as seguintes medidas devem ser tomadas:

  1. Certifique-se de que o espaço de armazenamento não esteja cheio - fora do horário de pico, é mais apropriado manter o uso de memória do Redis abaixo de 30%.
  2. Para os dados que precisam ser persistidos, a operação de persistência deve ser executada no tempo e deve haver mecanismos de log, monitoramento e alarme correspondentes para evitar a perda de dados não persistentes
  3. Balanceamento de carga - pode ser tratado com Redis-Cluster ou outro middleware

おすすめ

転載: blog.csdn.net/qq_23937195/article/details/108911772