Análisis de la codificación interna de los cinco tipos de datos en Redis (1, String)

imagen



Visión general


Usualmente usamos Redis a nivel de usuario. Podemos operar un par clave-valor sin pensar en ello para acceder a los datos de manera conveniente. Se siente muy conveniente. Pero, ¿sabe cómo se almacenan y codifican estos datos entre bastidores? Una comprensión clara de este problema tendrá una importancia fundamental para que podamos usar Redis de manera más eficiente. Al comienzo de este artículo, combinaremos el código fuente de Redis para analizar el mecanismo de codificación interno de los cinco tipos de datos de Redis, uno por uno.

  • Entorno experimental: Redis 4.0.10

Nota:  Este artículo se publicó por primera vez en Mi cuenta pública CodeSheep , puede presionar prolongadamente o escanear la advertencia a continuación para suscribirse ↓ ↓ ↓        

imagen




Descripción general de la codificación interna de los tipos de datos de Redis


Para los cinco  tipos de datos de Redis de uso común  (String, Hash, List, Set, sorted set), cada tipo de datos proporciona al  menos dos  formatos de codificación interna, y la elección de la codificación interna para cada tipo de datos  es completamente para los usuarios Transparente , Redis seleccionará de forma adaptativa un formato de codificación interno más optimizado de acuerdo con la cantidad de datos.

Si desea ver el formato de codificación interno de una clave, puede usar  OBJECT ENCODING keynamecomandos para hacerlo, como:

127.0.0.1:6379>  
127.0.0.1:6379> establecer foo bar 
OK 
127.0.0.1:6379>  
127.0.0.1:6379> codificación de objeto foo // Ver la codificación de un valor de clave de Redis 
"embstr" 
127.0.0.1:6379>  
127.0.0.1:6379>

Redis Cada valor de clave de se  guarda internamente con un nombre llamado  redisObjectesta estructura de lenguaje C, y el código es el siguiente:

imagen

La explicación es la siguiente:

  • type: Representa el tipo de datos del valor de la clave, incluidos String, List, Set, ZSet, Hash

  • encoding: Representa el método de codificación interno del valor de la clave. Del código fuente de Redis, los valores actuales son los siguientes:

#define OBJ_ENCODING_RAW 0 / * Representación sin procesar * / 
#define OBJ_ENCODING_INT 1 / * Codificado como entero * / 
#define OBJ_ENCODING_HT 2 / * Codificado como tabla hash * / 
#define OBJ_ENCODING_ZIPMAP 3 / * Codificado como zipmap_LJ_EDLODISTING * / 
#definemap Ya no se utiliza: codificación de lista antigua. * / 
#Define OBJ_ENCODING_ZIPLIST 5 / * codificado como ZipList * / 
#define OBJ_ENCODING_INTSET 6 / * codificado como intset * / 
#define OBJ_ENCODING_SKIPLIST 7 / * codificado como skiplist * / 
#define OBJ_ENCODING_EMBSTR 8 / * Embedded sds serie de codificación * / 
#define OBJ_ENCODING_QUICKLIST 9 / * Codificado como lista enlazada de tirolistas * /
  • refcount: Indica el número de referencias al valor de la clave, es decir, varias claves pueden hacer referencia a un valor de clave.

En este artículo, comenzaremos con la codificación interna del tipo String más básico en Redis.




La codificación interna del tipo String


字符串是 Redis最基本的数据类型,Redis 中字符串对象的编码可以是 int, raw 或者 embstr 中的某一种,分别介绍如下:

  • int 编码:保存long 型的64位有符号整数

  • embstr 编码:保存长度小于44字节的字符串

  • raw 编码:保存长度大于44字节的字符串

我们不妨来做个实验实际看一下:

imagen

实际情况就是 Redis 内部会根据用户给的不同键值而使用不同的编码格式,而这一切对用户完全透明!

Redis 是使用 SDS(“简单动态字符串”)这个结构体来存储字符串,代码里定义了 5种 SDS结构体:

struct __attribute__ ((__packed__)) sdshdr5 {
    unsigned char flags; /* 3 lsb of type, and 5 msb of string length */
    char buf[];
};
struct __attribute__ ((__packed__)) sdshdr8 {
    uint8_t len; /* used */
    uint8_t alloc; /* excluding the header and null terminator */
    unsigned char flags; /* 3 lsb of type, 5 unused bits */
    char buf[];
};
struct __attribute__ ((__packed__)) sdshdr16 {
    uint16_t len; /* used */
    uint16_t alloc; /* excluding the header and null terminator */
    unsigned char flags; /* 3 lsb of type, 5 unused bits */
    char buf[];
};
struct __attribute__ ((__packed__)) sdshdr32 {
    uint32_t len; /* used */
    uint32_t alloc; /* excluding the header and null terminator */
    unsigned char flags; /* 3 lsb of type, 5 unused bits */
    char buf[];
};
struct __attribute__ ((__packed__)) sdshdr64 {
    uint64_t len; /* used */
    uint64_t alloc; /* excluding the header and null terminator */
    unsigned char flags; /* 3 lsb of type, 5 unused bits */
    char buf[];
};

可以看出,除了结构体字段数据类型的不同,其字段含义相差无几,其中:

  • len:字符串的长度(实际使用的长度)

  • alloc:分配内存的大小

  • flags:标志位,低三位表示类型,其余五位未使用

  • buf:字符数组

了解了这些基本的数据结构以后,我们就来看看上面例子中:

  • set foo 123

  • set foo abc

  • set foo abcdefghijklmnopqrstuvwxyzabcdeffasdffsdaadsx

这三种情形下 Redis 内部到底是怎么存数据的!




INT 编码格式


命令示例: setfoo123

当字符串键值的内容可以用一个 64位有符号整形 来表示时,Redis会将键值转化为 long型来进行存储,此时即对应 OBJ_ENCODING_INT 编码类型。

OBJ_ENCODING_INT 编码类型内部的内存结构可以形象地表示如下:

imagen

而且 Redis 启动时会预先建立 10000 个分别存储 0~9999 的 redisObject 变量作为共享对象,这就意味着如果 set字符串的键值在 0~10000 之间的话,则可以 直接指向共享对象 而不需要再建立新对象,此时键值不占空间!

因此,当执行如下指令时:

set key1 100set key2 100

其实 key1 和 key2 这两个键值都直接引用了一个 Redis 预先已建立好的共享 redisObject 对象,就像下面这样:

imagen

源码之前,了无秘密,我们再对照下面的源码,来理解一下上述过程

image.png




EMBSTR 编码格式


命令示例: setfoo abc

Redis 在保存长度小于 44 字节的字符串时会采用 OBJ_ENCODING_EMBSTR编码方式,口说无凭,我们来瞅瞅源码:

image.png

从上述代码中很容易看出,对于长度小于 44的字符串,Redis 对键值采用 OBJ_ENCODING_EMBSTR 方式,EMBSTR 顾名思义即:embedded string,表示嵌入式的String。从内存结构上来讲 即字符串 sds结构体与其对应的 redisObject 对象分配在 同一块连续的内存空间,这就仿佛字符串 sds 嵌入在 redisObject 对象之中一样,这一切从下面的代码即可清楚地看到:

imagen

因此,对于指令 setfoo abc 所设置的键值,其内存结构示意图如下:

imagen




RAW 编码格式


指令示例: setfoo abcdefghijklmnopqrstuvwxyzabcdeffasdffsdaadsx

Al igual que en el ejemplo de instrucción, cuando el valor de clave de la cadena  es  una  cadena muy larga con una longitud mayor que  44 , Redis cambiará la codificación interna de la clave al  OBJ_ENCODING_RAW formato.  La diferencia con la codificación anterior  OBJ_ENCODING_EMBSTRes que el carácter dinámico es en este momento La memoria de la cadena sds y la memoria del redisObject del que depende ya  no son continuas  . Tomando el comando anterior como ejemplo, la estructura de memoria de su valor clave es la siguiente:

imagen

Con esto concluye la codificación interna del tipo de datos String más básico, ¡qué tal, todavía es bastante fácil de entender!

Posteriormente, continuaremos analizando el formato de codificación interno del tipo de datos Hash en Redis.




Posdata


Debido a la capacidad limitada, si hay errores o irregularidades, por favor, critíquelos y corríjalos, y aprendan y comuníquense juntos.

  • Mi blog personal: www.codesheep.cn


Si está interesado, también puede tomarse un tiempo para leer el artículo del autor sobre contenedorización y microservicios:



En el artículo original más pragmático, capaz de leer y reproducible para hacer público el número CodeSheep , suscríbete ⬇️⬇️⬇️

imagen


Supongo que te gusta

Origin blog.51cto.com/15127562/2663987
Recomendado
Clasificación