Objetos de Design e Implementação do Redis

Um: objetos no Redis

  • O Redis usa objetos para representar as chaves e os valores no banco de dados. Sempre que criarmos um novo par de valores-chave no banco de dados Redis, criaremos pelo menos dois objetos. Um objeto é usado como a chave do par de valores-chave (objeto-chave). Outro objeto é usado como o valor do par de valores-chave (objeto de valor).

Cada objeto no Redis é representado por uma estrutura redisObject.Os três atributos relacionados aos dados salvos nessa estrutura são o atributo type, o atributo encoding e o atributo ptr.

typedef struct redisObject {
    //类型
    unsigned type:4;
    //编码
    unsigned encoding:4;
    //最近访问的时间
    unsigned lru:LRU_BITS; /* LRU time (relative to global lru_clock) or
                            * LFU data (least significant 8 bits frequency
                            * and most significant 16 bits access time). */
    //引用计数
    int refcount;
    //指向底层实现数据结构的指针
    void *ptr;
} robj;

1: tipo

Existem cinco tipos de objetos:

O par de valor-chave salvo pelo redis, a chave é sempre um objeto de string e o valor pode ser um de objetos de string, objetos de lista, objetos de hash, objetos de coleção e objetos de coleção ordenados, então:

  • Quando chamamos uma chave de banco de dados de objeto string, o valor correspondente à chave de banco de dados que representamos é um objeto string.
  • Quando chamamos uma chave de banco de dados de objeto de lista, o valor correspondente à chave de banco de dados que representamos é um objeto de lista.

2: codificação e implementação subjacente

O ponteiro ptr do objeto aponta para a estrutura de dados de implementação subjacente do objeto, e essas estruturas de dados são determinadas pelo atributo de codificação do objeto.

O atributo encoding registra a codificação usada pelo objeto, o que significa que de acordo com essa codificação, você pode saber qual estrutura de dados o objeto usa como estrutura de dados subjacente

Pelo menos duas codificações diferentes são usadas para cada tipo de objeto

Defina a codificação usada pelo objeto por meio do atributo encoding, em vez de uma codificação fixa associada a um tipo específico de objeto, o que melhora muito a flexibilidade e a eficiência do Redis, porque o Redis pode definir diferentes configurações para um objeto de acordo com diferentes cenários. otimizar a eficiência do objeto em uma determinada cena.

3: objeto String

A codificação do objeto string pode ser int, raw ou embstr

  • Se um objeto string salvar um valor inteiro, e o valor inteiro puder ser representado pelo tipo longo, então o objeto string salvará o valor inteiro no atributo ptr da estrutura do objeto string (converter void * para longo), e definir o codificação do objeto string para int.

  • Se um objeto string armazena uma string e o comprimento da string é maior que 32 bytes, então o objeto string usará uma string dinâmica simples (SDS) para salvar o valor da string, e o caractere A codificação do objeto string está definido como bruto.

  • Se um objeto string armazenar uma string e o comprimento da string for menor ou igual a 32 bytes, o objeto string usará a codificação embstr para salvar o valor da string.

A codificação Embstr é um método de codificação otimizado especialmente usado para salvar strings curtas. Esta codificação, como a codificação bruta, usa a estrutura redisObject e a estrutura sdshdr, enquanto a codificação embstr aloca um espaço contínuo chamando uma função de alocação de memória. Espécies de espaço incluem a estrutura redisObject e sdshdr estrutura.

As vantagens do embstr em relação ao cru são:

  • O número de alocações de memória necessárias para a codificação embstr para criar um objeto string mudou de dois para um em bruto.
  • Para liberar um objeto de string codificado em embstr, basta chamar a função de liberação de memória uma vez, enquanto a liberação de um objeto de string codificado bruto precisa chamar a função de liberação de memória duas vezes.
  • Todos os dados da string codificada embstr estão em uma memória contígua, então este objeto string codificado pode utilizar melhor as vantagens do cache do que o objeto string codificado bruto.

O número de ponto flutuante representado pelo tipo duplo longo também é armazenado como um valor de string no redis.

  • Ao salvar, vamos converter o valor do ponto flutuante em um valor de string para salvar
  • Ao realizar as operações, vamos converter o valor da string em um valor de ponto flutuante e, em seguida, realizar a operação, o resultado obtido é convertido em um valor da string e, em seguida, salvo.

3.1: Conversão de codificação de objeto de string

Objetos de string codificados por int e objetos de string codificados por embstr serão convertidos em strings codificados brutos se as condições forem atendidas.

  • Para objetos codificados por int, se realizarmos uma série de operações de modo que o valor salvo pelo objeto não seja mais um valor inteiro, mas uma string, a codificação do objeto string mudará de int para raw.
  • A string codificada por embstr é, na verdade, somente leitura. Quando executamos o comando de modificação no objeto string codificado por embstr, o programa primeiro altera a codificação do objeto string para raw e, em seguida, executa a operação de modificação.

3.2: Implementação de comandos de string

4: Objeto de lista

A codificação do objeto de lista pode ser ziplist ou linkedlist

  • O objeto de lista codificado ziplist usa uma lista compactada como a implementação subjacente, e cada nó de lista compactado (entrada) armazena um elemento de lista.

  • O objeto de lista codificado pelo ziplist usa uma lista vinculada dupla como a camada inferior. Cada nó de lista de dupla extremidade armazena um objeto de string e cada objeto de string armazena um elemento de lista

4.1: Conversão de codificação

  1. O comprimento de todos os elementos de string armazenados no objeto de lista é inferior a 64 bytes
  2. O número de elementos armazenados no objeto de lista é inferior a 512, e o objeto de lista que não pode atender a essas duas condições precisa usar a codificação de lista vinculada
list-max-ziplist-value 64
list-max-ziplist-entries 512

4.2: Implementação do Comando de Lista

5: objeto Hash

A codificação do objeto hash pode ser ziplist ou hashtable.

  • O objeto hash codificado por ziplist é implementado com a lista compactada como a camada inferior. Sempre que houver um novo par de valor-chave a ser adicionado ao objeto hash, o programa primeiro empurrará o nó da lista compactada da chave salva para o final da lista compactada e, em seguida, envie o nó da lista compactada com o valor salvo para o final da tabela da lista compactada.

Portanto, possui as seguintes características:

1: Dois nós que salvam o mesmo par de valores-chave estão sempre próximos um do outro, o nó que salva a chave é o primeiro e o nó que salva o valor é o posterior.

2: Os pares de valores-chave adicionados primeiro ao objeto hash serão colocados no topo da lista compactada e os pares de valores-chave adicionados posteriormente ao objeto hash serão colocados no final da lista compactada.

  • O objeto hash codificado por hashtable usa um dicionário como a implementação subjacente, e cada par de valor-chave no objeto hash é armazenado usando o par de valor-chave do dicionário.
  1. Cada chave no dicionário é um objeto de string, e o valor do par chave-valor é armazenado no objeto
  2. Cada valor no dicionário é um objeto de string, e o valor do par de valores-chave é armazenado no objeto

5.1: Conversão de codificação de caracteres

  • O comprimento das strings de chave e valor de todos os pares de chave-valor salvos pelo objeto hash é inferior a 64 bytes
  • O número de pares de valores-chave salvos pelo objeto hash é menor que 512, e o objeto hash que não pode atender a essas duas condições precisa usar a codificação hashtable
# Hashes are encoded using a memory efficient data structure when they have a
# small number of entries, and the biggest entry does not exceed a given
# threshold. These thresholds can be configured using the following directives.
hash-max-ziplist-entries 512
hash-max-ziplist-value 64

5.2: Implementação do Comando Hash

6: Objetos de coleção

A codificação do objeto da coleção pode ser intset ou hashtable.

  • O objeto de coleção codificado por intset usa a coleção de inteiros como a implementação subjacente e todos os elementos contidos no objeto de coleção são armazenados na coleção de inteiros.
  • O objeto de coleção codificado por hashtable usa um dicionário como a implementação subjacente. Cada chave do dicionário é um objeto string, cada objeto string contém um elemento de coleção e os valores do dicionário são todos definidos como NULL.

6.1: Conversão de codificação

  • Todos os elementos salvos pelo objeto da coleção são valores inteiros
  • O número de elementos salvos pelo objeto da coleção não excede 512. Os objetos da coleção que não podem atender a essas duas condições precisam usar codificação hashtable
# Sets have a special encoding in just one case: when a set is composed
# of just strings that happen to be integers in radix 10 in the range
# of 64 bit signed integers.
# The following configuration setting sets the limit in the size of the
# set in order to use this special memory saving encoding.
set-max-intset-entries 512

6.2: Implementação de comandos coletivos

7: coleção ordenada de objetos

A codificação do objeto da coleção pode ser intset ou skiplist.

O objeto hash codificado por ziplist é implementado com a lista compactada como a camada inferior. Cada elemento definido é salvo por dois nós de lista compactada próximos um do outro. O primeiro nó salva os membros do elemento e o segundo nó salva a pontuação do elemento valor.

As pontuações dos elementos definidos da lista compactada são classificadas de pequeno a grande. Os elementos com pontuações menores estão mais próximos do topo da tabela e os elementos com pontuações maiores estão mais próximos do final da tabela.

  • O objeto de conjunto ordenado codificado por skiplist usa a estrutura zset como a implementação subjacente. Uma estrutura zset contém um dicionário e uma lista de pular.
typedef struct zset {
    dict *dict;
    zskiplist *zsl;
} zset;

O dicionário em zset cria um mapeamento de membros para pontuações para um conjunto ordenado. Cada par de valores-chave no dicionário armazena um elemento de conjunto. A chave do dicionário armazena os membros do elemento, e o valor do dicionário armazena A pontuação do elemento, por meio do dicionário, pode-se encontrar a pontuação de um determinado membro em o (1).

A tabela de salto também salva os membros e pontuações dos elementos, e todos eles compartilham os mesmos membros de elemento e pontuações por meio de ponteiros. Nenhum membro duplicado e pontos serão gerados, então nenhuma memória extra será desperdiçada.

 

Nota: Elementos e pontos são realmente compartilhados.

7.1: Conversão de codificação

  • O comprimento de todos os membros do elemento salvos pelo objeto de coleção ordenado é inferior a 64 bytes
  • O número de elementos salvos pelo objeto de coleção ordenado é inferior a 128, e o objeto de coleção ordenado que não pode atender a essas duas condições precisa usar a codificação skiplist
# Similarly to hashes and lists, sorted sets are also specially encoded in
# order to save a lot of space. This encoding is only used when the length and
# elements of a sorted set are below the following limits:
zset-max-ziplist-entries 128
zset-max-ziplist-value 64

7.2: Implementação de comandos de conjunto ordenado

8: Verificação de tipo e polimorfismo de comando

Existem dois tipos de comandos usados ​​pelo Redis para manipular chaves. Um tipo pode ser executado para qualquer tipo de chave. Uma é executar apenas nas teclas do tipo de característica.

  • DEL, EXPIRE, RENAME, TYEP, OBJECT e outros comandos são úteis para qualquer tecla

 

8.1: Verificação de tipo

8.2: A realização de comandos polimórficos

DEL, EXPIRE, RENAME, TYEP e OBJECT são para o polimorfismo do tipo, enquanto set é para o polimorfismo da codificação.

9: Recuperação de memória

Quando o valor de refcount na estrutura de redisobject torna-se 0, a memória ocupada pelo objeto será liberada.

9.1: API para modificar a contagem de referência

função incrRefCount

void incrRefCount(robj *o) {
    if (o->refcount < OBJ_FIRST_SPECIAL_REFCOUNT) {
        o->refcount++;
    } else {
        if (o->refcount == OBJ_SHARED_REFCOUNT) {
            /* Nothing to do: this refcount is immutable. */
        } else if (o->refcount == OBJ_STATIC_REFCOUNT) {
            serverPanic("You tried to retain an object allocated in the stack");
        }
    }
}

função decrRefCount

void decrRefCount(robj *o) {
    if (o->refcount == 1) {
        switch(o->type) {
        case OBJ_STRING: freeStringObject(o); break;
        case OBJ_LIST: freeListObject(o); break;
        case OBJ_SET: freeSetObject(o); break;
        case OBJ_ZSET: freeZsetObject(o); break;
        case OBJ_HASH: freeHashObject(o); break;
        case OBJ_MODULE: freeModuleObject(o); break;
        case OBJ_STREAM: freeStreamObject(o); break;
        default: serverPanic("Unknown object type"); break;
        }
        zfree(o);
    } else {
        if (o->refcount <= 0) serverPanic("decrRefCount against refcount <= 0");
        if (o->refcount != OBJ_SHARED_REFCOUNT) o->refcount--;
    }
}

10: Compartilhamento de objetos

Quando o redis é inicializado, um objeto string de 0 a 9999 é criado, para que o objeto seja compartilhado.Quando objetos diferentes são compartilhados, o refcount aumentará.

11: O tempo de inatividade do objeto

O atributo lru do objeto redisObject registra a hora da última visita, e a hora da última visita pode ser calculada subtraindo a hora da última visita da hora atual.

 

Acho que você gosta

Origin blog.csdn.net/qq_37469055/article/details/114683053
Recomendado
Clasificación