Анализ внутреннего кодирования строкового типа Redis

Redis задняя часть контейнер Docker
Анализ внутреннего кодирования строкового типа Redis

Обзор

Мы обычно используем Redis на уровне пользователя, мы можем работать с парой ключ-значение, не думая о легком доступе к данным, что очень удобно. Но знаете ли вы, как эти данные хранятся и кодируются за кулисами? Четкое понимание этой проблемы поможет нам более эффективно использовать Redis. В начале этой статьи мы объединим исходный код Redis, чтобы последовательно обсудить внутренний механизм кодирования пяти основных типов данных Redis.

  • Экспериментальная среда: Redis 4.0.10

Примечание:Эта статья была впервые опубликована на моем официальном аккаунтеCodeSheep,МожетНажмитеилисканированиеследующеебудь остороженЗаходи подписывайся ↓ ↓ ↓

CodeSheep · 程序羊



Обзор внутреннего кодирования типов данных Redis

Общий для Redis5типы данных (String, Hash, List, Set, sorted set), каждый из которых обеспечиваетпо меньшей мере, дваВнутренний формат кодирования и выбор метода внутреннего кодирования для каждого типа данныхполностью прозрачен для пользователя, Redis будет адаптивно выбирать более оптимизированный внутренний формат кодирования в зависимости от объема данных.

Если вы хотите увидеть внутренний формат кодировки ключа, вы можете использоватьOBJECT ENCODING keynameинструкции, такие как:

127.0.0.1:6379> 
127.0.0.1:6379> set foo bar
OK
127.0.0.1:6379> 
127.0.0.1:6379> object encoding foo  // 查看某个Redis键值的编码
"embstr"
127.0.0.1:6379> 
127.0.0.1:6379> 

RedisКаждое значение ключа внутренне используется с именем, называемымredisObjectЭта структура языка C сохраняется, и ее код выглядит следующим образом:

redisObject 结构体

Объяснение следующее:

  • type: Типы данных, представляющие значения ключей, включая String, List, Set, ZSet, Hash.
  • encoding: указывает внутренний метод кодирования значения ключа.Из исходного кода Redis текущие значения следующие:
#define OBJ_ENCODING_RAW 0        /* Raw representation */
#define OBJ_ENCODING_INT 1        /* Encoded as integer */
#define OBJ_ENCODING_HT 2         /* Encoded as hash table */
#define OBJ_ENCODING_ZIPMAP 3     /* Encoded as zipmap */
#define OBJ_ENCODING_LINKEDLIST 4 /* No longer used: old list encoding. */
#define OBJ_ENCODING_ZIPLIST 5    /* Encoded as ziplist */
#define OBJ_ENCODING_INTSET 6     /* Encoded as intset */
#define OBJ_ENCODING_SKIPLIST 7   /* Encoded as skiplist */
#define OBJ_ENCODING_EMBSTR 8     /* Embedded sds string encoding */
#define OBJ_ENCODING_QUICKLIST 9  /* Encoded as linked list of ziplists */
  • refcount: указывает количество ссылок на ключ, т. е. на ключ может ссылаться несколько ключей.

В этой статье мы начнем с внутреннего кодирования самого простого типа String в Redis!



Внутренняя кодировка типа String

Строка — это самый основной тип данных Redis, и кодирование строкового объекта в Redis может бытьint,rawилиembstrОдин из них описывается следующим образом:

  • кодировка int: содержит 64-битное целое число со знаком типа long
  • кодировка embstr: сохраняет строки длиной менее 44 байт.
  • необработанное кодирование: сохраняет строки длиннее 44 байт

Давайте посмотрим на реальный эксперимент:

String的各种内部编码格式

Реальная ситуация такова, что Redis будет использовать разные форматы кодирования в соответствии с разными значениями ключей, заданными пользователем, и все это совершенно прозрачно для пользователя!

Редис используетSDS(«Простая динамическая строка») Эта структура используется для хранения строк, определенных в коде.5 видовСтруктура паспорта безопасности:

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

Пример команды:set foo 123

Когда содержимое строкового значения ключа можно использовать с64-битное целое число со знакомДля представления Redis преобразует значение ключа в длинный тип для хранения, который соответствуетOBJ_ENCODING_INTтип кодирования.

OBJ_ENCODING_INTСтруктуру памяти внутри типа кодирования можно представить визуально следующим образом:

set foo 123 时键值的内存结构

И Redis будет предварительно установлен при запуске.10000отдельное хранилище0~9999Переменная redisObject используется как общий объект, что означает, что если значение ключа заданной строки находится в диапазоне от 0 до 10000, вы можетеуказывать непосредственно на общий объектНе нужно создавать новый объект, значение ключа в это время не занимает места!

Поэтому при выполнении следующих инструкций:

set key1 100
set key2 100

фактическиkey1иkey2Оба ключа напрямую ссылаются на общий redisObject, предварительно установленный Redis, например:

共享对象

Перед исходным кодом нет секретов, давайте сравним следующий исходный код, чтобы понять описанный выше процесс.

INT编码的源码



Формат кодирования EMBSTR

Пример команды:set foo abc

Redis сохраняет длину меньше, чем44Строка байтов будет использоваться, когдаOBJ_ENCODING_EMBSTRМетод кодирования голословен, давайте посмотрим на исходный код:

EMBSTR编码的判断条件

Из приведенного выше кода легко увидеть, что для строк длиной менее 44 Redis используетOBJ_ENCODING_EMBSTRМетод EMBSTR, как следует из его названия:embedded string, представляющий встроенную строку. С точки зрения структуры памяти, то есть структура строки sds и соответствующий ей объект redisObject размещаются водно и то же непрерывное пространство памяти, это как если бы строка sds была встроена в объект redisObject, что ясно из приведенного ниже кода:

embedded string

Поэтому для инструкцииset foo abcУстановленное значение ключа, схема его структуры памяти выглядит следующим образом:

set foo abc时的键值内存结构



Формат кодирования RAW

Пример команды:set foo abcdefghijklmnopqrstuvwxyzabcdeffasdffsdaadsx

Как и в примере с директивой, когда ключевое значение строки длиннее, чем44изсупер длинная струна, Redis изменит внутреннюю кодировку значения ключа наOBJ_ENCODING_RAWформат, который аналогичен приведенному вышеOBJ_ENCODING_EMBSTRРазница в способе кодирования в том, что память динамической строки sds и память redisObject, от которого она зависит, находятся в это время.Память больше не является непрерывной, с участиемset foo abcdefghijklmnopqrstuvwxyzabcdeffasdffsdaadsxНапример, структура памяти его значения ключа выглядит следующим образом:

set foo abcdefghijklmnopqrstuvwxyzabcdeffasdffsdaadsx时键值的内存结构

На этом я закончил внутреннюю кодировку самого основного типа данных String, как это, понять еще несложно!

Позже мы продолжим анализ внутреннего формата кодирования типа данных Hash в Redis.



Постскриптум

Из-за ограниченных возможностей, если есть ошибки или неуместность, пожалуйста, критикуйте и исправьте их, учитесь и обменивайтесь мнениями вместе!

Дополнительные статьи автора о SpringBt находятся здесь:


Если вам интересно, вы также можете уделить время прочтению некоторых статей автора о контейнеризации и микросервисах:


МожетНажмитеилисканированиеследующеебудь остороженподписыватьсяCodeSheep, получить большеПрагматичный, понятный, воспроизводимыйИсходный текст ↓↓↓

CodeSheep · 程序羊