Обзор
Мы обычно используем Redis на уровне пользователя, мы можем работать с парой ключ-значение, не думая о легком доступе к данным, что очень удобно. Но знаете ли вы, как эти данные хранятся и кодируются за кулисами? Четкое понимание этой проблемы поможет нам более эффективно использовать Redis. В начале этой статьи мы объединим исходный код Redis, чтобы последовательно обсудить внутренний механизм кодирования пяти основных типов данных Redis.
- Экспериментальная среда: Redis 4.0.10
Примечание:Эта статья была впервые опубликована на моем официальном аккаунте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 сохраняется, и ее код выглядит следующим образом:
Объяснение следующее:
-
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 байт
Давайте посмотрим на реальный эксперимент:
Реальная ситуация такова, что 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
Структуру памяти внутри типа кодирования можно представить визуально следующим образом:
И Redis будет предварительно установлен при запуске.10000отдельное хранилище0~9999Переменная redisObject используется как общий объект, что означает, что если значение ключа заданной строки находится в диапазоне от 0 до 10000, вы можетеуказывать непосредственно на общий объектНе нужно создавать новый объект, значение ключа в это время не занимает места!
Поэтому при выполнении следующих инструкций:
set key1 100
set key2 100
фактическиkey1иkey2Оба ключа напрямую ссылаются на общий redisObject, предварительно установленный Redis, например:
Перед исходным кодом нет секретов, давайте сравним следующий исходный код, чтобы понять описанный выше процесс.
Формат кодирования EMBSTR
Пример команды:set foo abc
Redis сохраняет длину меньше, чем44Строка байтов будет использоваться, когдаOBJ_ENCODING_EMBSTR
Метод кодирования голословен, давайте посмотрим на исходный код:
Из приведенного выше кода легко увидеть, что для строк длиной менее 44 Redis используетOBJ_ENCODING_EMBSTR
Метод EMBSTR, как следует из его названия:embedded string, представляющий встроенную строку. С точки зрения структуры памяти, то есть структура строки sds и соответствующий ей объект redisObject размещаются водно и то же непрерывное пространство памяти, это как если бы строка sds была встроена в объект redisObject, что ясно из приведенного ниже кода:
Поэтому для инструкцииset foo abc
Установленное значение ключа, схема его структуры памяти выглядит следующим образом:
Формат кодирования RAW
Пример команды:set foo abcdefghijklmnopqrstuvwxyzabcdeffasdffsdaadsx
Как и в примере с директивой, когда ключевое значение строки длиннее, чем44изсупер длинная струна, Redis изменит внутреннюю кодировку значения ключа наOBJ_ENCODING_RAW
формат, который аналогичен приведенному вышеOBJ_ENCODING_EMBSTR
Разница в способе кодирования в том, что память динамической строки sds и память redisObject, от которого она зависит, находятся в это время.Память больше не является непрерывной, с участиемset foo abcdefghijklmnopqrstuvwxyzabcdeffasdffsdaadsx
Например, структура памяти его значения ключа выглядит следующим образом:
На этом я закончил внутреннюю кодировку самого основного типа данных String, как это, понять еще несложно!
Позже мы продолжим анализ внутреннего формата кодирования типа данных Hash в Redis.
Постскриптум
Из-за ограниченных возможностей, если есть ошибки или неуместность, пожалуйста, критикуйте и исправьте их, учитесь и обменивайтесь мнениями вместе!
Дополнительные статьи автора о SpringBt находятся здесь:
- Полугодовой технологический блог новичка
- Практика ведения журнала Spring Boot
- Стандартный опыт Spring Boot Admin2.0
- Мониторинг приложений Spring Boot на практике
- Приложения SpringBoot развертываются во внешнем контейнере Tomcat.
- Практика поисковой системы ElasticSearch в SpringBt
- Предварительное изучение совместного программирования Kotlin+SpringBoot
- Элегантное кодирование SpringBoot: благословение Ломбока
Если вам интересно, вы также можете уделить время прочтению некоторых статей автора о контейнеризации и микросервисах:
- Используйте стек технологий K8S для создания личного частного облака Серийная статья
- Подробная конфигурация сервера Nginx из списка конфигураций
- Строительство центра мониторинга визуализации контейнеров Docker
- Использование ELK для создания контейнерного центра журналов приложений Docker
- Практика фреймворка RPC: Apache Thrift
- Практика фреймворка RPC: Google gRPC
- Построение микросервисного центра отслеживания цепочки вызовов
- Контейнеры Docker обмениваются данными между хостами
- Предварительное исследование кластера Docker Swarm
- Несколько рекомендаций по эффективному написанию Dockerfile
МожетНажмитеилисканированиеследующеебудь остороженподписыватьсяCodeSheep, получить большеПрагматичный, понятный, воспроизводимыйИсходный текст ↓↓↓