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
- O comprimento de todos os elementos de string armazenados no objeto de lista é inferior a 64 bytes
- 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.
- Cada chave no dicionário é um objeto de string, e o valor do par chave-valor é armazenado no objeto
- 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.