Objetos de diseño e implementación de Redis

Uno: Objetos en Redis

  • Redis usa objetos para representar las claves y valores en la base de datos. Siempre que creamos un nuevo par clave-valor en la base de datos de Redis, crearemos al menos dos objetos. Un objeto se usa como clave del par clave-valor (objeto clave) Otro objeto se utiliza como valor del par clave-valor (objeto de valor).

Cada objeto en Redis está representado por una estructura redisObject. Los tres atributos relacionados con los datos guardados en esta estructura son el atributo de tipo, el atributo de codificación y el 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

Hay cinco tipos de objetos:

El par clave-valor guardado por redis, la clave es siempre un objeto de cadena, y el valor puede ser uno de entre objetos de cadena, objetos de lista, objetos hash, objetos de colección y objetos de colección ordenados, por lo que:

  • Cuando llamamos a una clave de base de datos un objeto de cadena, el valor correspondiente a la clave de base de datos que representamos es un objeto de cadena.
  • Cuando llamamos a una clave de base de datos un objeto de lista, el valor correspondiente a la clave de base de datos que representamos es un objeto de lista.

2: codificación e implementación subyacente

El puntero ptr del objeto apunta a la estructura de datos de implementación subyacente del objeto, y estas estructuras de datos están determinadas por el atributo de codificación del objeto.

El atributo de codificación registra la codificación utilizada por el objeto, lo que significa que de acuerdo con esta codificación, puede saber qué estructura de datos utiliza el objeto como estructura de datos subyacente.

Se utilizan al menos dos codificaciones diferentes para cada tipo de objeto

Establezca la codificación utilizada por el objeto a través del atributo de codificación, en lugar de una codificación fija asociada con un tipo específico de objeto, lo que mejora en gran medida la flexibilidad y eficiencia de Redis, porque Redis puede establecer diferentes configuraciones para un objeto de acuerdo con diferentes escenarios. optimizar la eficiencia del objeto en una determinada escena.

3: objeto de cadena

La codificación del objeto de cadena puede ser int, raw o embstr

  • Si un objeto de cadena guarda un valor entero, y el valor entero puede ser representado por el tipo largo, entonces el objeto de cadena guardará el valor entero en el atributo ptr de la estructura del objeto de cadena (convertir void * a largo), y establecerá el codificación del objeto de cadena en int.

  • Si un objeto de cadena almacena una cadena, y la longitud de la cadena es mayor de 32 bytes, entonces el objeto de cadena utilizará una cadena dinámica simple (SDS) para guardar el valor de la cadena y el carácter La codificación del objeto de cadena está configurado en crudo.

  • Si un objeto de cadena almacena una cadena y la longitud de la cadena es menor o igual a 32 bytes, entonces el objeto de cadena utilizará la codificación embstr para guardar el valor de la cadena.

La codificación embstr es un método de codificación optimizado que se utiliza especialmente para guardar cadenas cortas. Esta codificación, como la codificación sin formato, utiliza la estructura redisObject y la estructura sdshdr, mientras que la codificación embstr asigna un espacio continuo llamando a una función de asignación de memoria, las especies de espacio incluyen la estructura redisObject y sdshdr estructura.

Las ventajas de embstr sobre raw son:

  • El número de asignaciones de memoria necesarias para la codificación embstr para crear un objeto de cadena ha cambiado de dos a uno en bruto.
  • Para liberar un objeto de cadena codificado en embstr solo necesita llamar a la función de liberación de memoria una vez, mientras que liberar un objeto de cadena codificado sin formato necesita llamar a la función de liberación de memoria dos veces.
  • Todos los datos de la cadena codificada embstr están en una memoria contigua, por lo que este objeto de cadena codificada puede utilizar mejor las ventajas de la caché que el objeto de cadena codificada sin formato.

El número de punto flotante representado por el tipo doble largo también se almacena como un valor de cadena en redis.

  • Al guardar, convertiremos el valor de punto flotante en un valor de cadena para guardar
  • Al realizar operaciones, convertiremos el valor de la cadena en un valor de punto flotante, y luego realizaremos la operación, el resultado obtenido se convierte en un valor de cadena y luego se guarda.

3.1: Conversión de codificación de objetos de cadena

Los objetos de cadena con codificación interna y los objetos de cadena con codificación embstr se convertirán en cadenas codificadas sin formato si se cumplen las condiciones.

  • Para los objetos codificados con int, si realizamos una serie de operaciones para que el valor guardado por el objeto ya no sea un valor entero, sino una cadena, entonces la codificación del objeto string cambiará de int a raw.
  • La cadena codificada por embstr es en realidad de solo lectura.Cuando ejecutamos el comando de modificación en el objeto de cadena codificado por embstr, el programa primero cambiará la codificación del objeto de cadena a raw y luego realizará la operación de modificación.

3.2: Implementación de comandos de cadena

4: objeto de lista

La codificación del objeto de lista puede ser ziplist o linklist

  • El objeto de lista codificado por ziplist utiliza una lista comprimida como implementación subyacente, y cada nodo de lista comprimida (entrada) almacena un elemento de lista.

  • El objeto de lista codificado por ziplist utiliza una lista enlazada de dos extremos como capa inferior. Cada nodo de lista de dos extremos almacena un objeto de cadena y cada objeto de cadena almacena un elemento de lista

4.1: Conversión de codificación

  1. La longitud de todos los elementos de cadena almacenados en el objeto de lista es inferior a 64 bytes.
  2. El número de elementos almacenados en el objeto de lista es inferior a 512, y el objeto de lista que no puede cumplir estas dos condiciones debe utilizar la codificación de lista enlazada
list-max-ziplist-value 64
list-max-ziplist-entries 512

4.2: Implementación del comando List

5: objeto hash

La codificación del objeto hash puede ser ziplist o hashtable.

  • El objeto hash codificado por ziplist se implementa con la lista comprimida como capa inferior. Siempre que haya un nuevo par clave-valor para agregar al objeto hash, el programa primero empujará el nodo de lista comprimida de la clave guardada hasta el final de la lista comprimida y, a continuación, empuje el nodo de la lista comprimida con el valor guardado al final de la tabla de la lista comprimida.

Por tanto, tiene las siguientes características:

1: Dos nodos que guardan el mismo par clave-valor siempre están cerca el uno del otro, el nodo que guarda la clave es el primero y el nodo que guarda el valor es el siguiente.

2: Los pares clave-valor agregados primero al objeto hash se colocarán al principio de la lista comprimida, y los pares clave-valor agregados posteriormente al objeto hash se colocarán al final de la lista comprimida.

  • El objeto hash codificado por tabla hash usa un diccionario como implementación subyacente, y cada par clave-valor en el objeto hash se almacena usando el par clave-valor del diccionario.
  1. Cada clave del diccionario es un objeto de cadena y el valor del par clave-valor se almacena en el objeto.
  2. Cada valor del diccionario es un objeto de cadena y el valor del par clave-valor se almacena en el objeto.

5.1: Conversión de codificación de caracteres

  • La longitud de las cadenas de clave y valor de todos los pares clave-valor guardados por el objeto hash es inferior a 64 bytes.
  • El número de pares clave-valor guardados por el objeto hash es inferior a 512, y el objeto hash que no puede cumplir estas dos condiciones debe utilizar la codificación de tabla hash.
# 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: Implementación del comando Hash

6: Objetos de colección

La codificación del objeto de colección puede ser intset o hashtable.

  • El objeto de colección codificado por intset usa la colección de enteros como implementación subyacente, y todos los elementos contenidos en el objeto de colección se almacenan en la colección de enteros.
  • El objeto de colección codificado en tabla hash utiliza un diccionario como implementación subyacente. Cada clave del diccionario es un objeto de cadena, cada objeto de cadena contiene un elemento de colección y los valores del diccionario se establecen en NULL.

6.1: Conversión de codificación

  • Todos los elementos guardados por el objeto de colección son valores enteros
  • El número de elementos guardados por el objeto de colección no supera los 512. Los objetos de colección que no pueden cumplir estas dos condiciones deben utilizar la codificación de tabla hash.
# 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: Implementación de comandos colectivos

7: Colección ordenada de objetos

La codificación del objeto de colección puede ser intset o skiplist.

El objeto hash codificado por ziplist se implementa con la lista comprimida como capa inferior. Cada elemento del conjunto se guarda mediante dos nodos de lista comprimidos uno al lado del otro. El primer nodo guarda los miembros del elemento y el segundo nodo guarda la puntuación del elemento. .valor.

Los puntajes de los elementos del conjunto de la lista comprimida se ordenan de pequeños a grandes. Los elementos con puntajes más pequeños están más cerca del encabezado de la tabla y los elementos con puntajes más altos están más cerca del final de la tabla.

  • El objeto de conjunto ordenado codificado por skiplist utiliza la estructura zset como implementación subyacente. Una estructura zset contiene un diccionario y una lista de omisión.
typedef struct zset {
    dict *dict;
    zskiplist *zsl;
} zset;

El diccionario en zset crea un mapeo de miembros a puntuaciones para un conjunto ordenado. Cada par clave-valor en el diccionario almacena un elemento de conjunto. La clave del diccionario almacena los miembros del elemento y el valor del diccionario almacena La puntuación del elemento, a través del diccionario, puede encontrar la puntuación de un miembro dado en o (1).

La tabla de salto también guarda los miembros y puntuaciones de los elementos, y todos comparten los mismos miembros de elementos y puntuaciones a través de punteros. No se generarán miembros ni puntos duplicados, por lo que no se desperdiciará memoria adicional.

 

Nota: Los elementos y los puntos se comparten en realidad.

7.1: Conversión de codificación

  • La longitud de todos los miembros del elemento guardados por el objeto de colección ordenado es inferior a 64 bytes.
  • El número de elementos guardados por el objeto de colección ordenado es inferior a 128, y el objeto de colección ordenado que no puede cumplir estas dos condiciones debe usar la codificación de lista de omisión
# 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: Implementación de comandos de conjuntos ordenados

8: Verificación de tipos y polimorfismo de comandos

Hay dos tipos de comandos que utiliza Redis para manipular claves, y un tipo se puede ejecutar para cualquier tipo de clave. Uno es ejecutar solo en las claves del tipo de característica.

  • DEL, EXPIRE, RENAME, TYEP, OBJECT y otros comandos son útiles para cualquier tecla

 

8.1: Verificación de tipo

8.2: La realización de comandos polimórficos

DEL, EXPIRE, RENAME, TYEP y OBJECT corresponden al polimorfismo de tipo, mientras que set corresponde al polimorfismo de codificación.

9: recuperación de memoria

Cuando el valor de refcount bajo la estructura redisobject se convierte en 0, se liberará la memoria ocupada por el objeto.

9.1: API para modificar el recuento de referencias

función 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");
        }
    }
}

Función 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: intercambio de objetos

Cuando se inicializa redis, se crea un objeto de cadena de 0 a 9999, para que el objeto sea compartido. Cuando se comparten diferentes objetos, el refcount aumentará.

11: El tiempo de inactividad del objeto.

El atributo lru del objeto redisObject registra la hora de la última visita, y la hora de la última visita se puede calcular restando la hora de la última visita de la hora actual.

 

Supongo que te gusta

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