Redis: структуры данных в памяти

Предпосылки: ACID, базовые структуры данных (массив, хеш-таблица, связный список), сеть (клиент/сервер, запрос/ответ).

Redis — это сервер структур данных в оперативной памяти с сетевым доступом. В отличие от реляционных СУБД, Redis не даёт ACID-гарантий и не хранит данные в таблицах. Вместо этого он предоставляет набор структур данных (строки, хеш-таблицы, списки, множества, упорядоченные множества, потоки), доступных по ключу через простой протокол. Всё хранится в RAM, операции выполняются в однопоточном event loop — простые команды часто укладываются в микросекунды, но реальная латентность зависит от сети, объёма данных, настроек персистентности и блокирующих команд.

Порядок изучения

Всё начинается с архитектуры: однопоточный event loop определяет, почему команды атомарны, почему одна медленная команда блокирует весь сервер и как Redis обрабатывает тысячи соединений без потоков. Без этой модели остальные темы повисают в воздухе — непонятно, откуда берётся атомарность и почему O(N)-команды опасны.

Далее — структуры данных. Каждая из них работает поверх event loop и использует внутренние кодировки (listpack, intset, skiplist), которые проще понять последовательно: String вводит SDS и механизм кодировок, Hash и List показывают listpack и пороги переключения, Set и Sorted Set добавляют intset и skip list, а Stream, HyperLogLog, Bitmap и Sub опираются на уже знакомые идеи. После структур данных естественно перейти к атомарности составных операций: EXEC и Lua-скрипты используют конкретные команды над конкретными структурами, и примеры без знания этих структур не читаются. Персистентность (RDB и AOF) не зависит от структур данных и атомарности — её можно читать параллельно с ними; достаточно понимать fork и copy-on-write и fsync.

Управление памятью требует знания всех типов данных, потому что внутренние кодировки и пороги переключения специфичны для каждого типа, а политики вытеснения работают на уровне ключей. Распределение (репликация, Sentinel, Cluster) опирается на персистентность — реплика получает данные через RDB-snapshot и AOF-поток — и на ограничения EXEC в кластере. Практические паттерны идут последними: кеширование использует eviction и TTL, очередиLIST и Stream, распределённые блокировкиLua и SET NX EX, rate limiting — INCR и ZRANGEBYSCORE. Без предыдущих тем эти рецепты превращаются в чёрные ящики.

Архитектура и модель исполнения

Однопоточная модель, работа с памятью и отличия от реляционных СУБД.

  • Что такое Redis — сравнение с PostgreSQL, философия выбора хранилища, CAP
  • Event loop — однопоточная модель, мультиплексирование, что блокирует цикл
  • Pipelining — батчинг команд для снижения сетевых задержек
  • Логические базы (SELECT) — db 0..N, зачем это нужно и почему в Cluster всегда db 0

Структуры данных

  • String — SDS, кодировки int/embstr/raw, INCR, TTL
  • Hash — listpack vs hashtable, пороги, HGETALL
  • List — quicklist (связный список из listpack-блоков), BRPOP
  • Set — intset vs hashtable, операции над множествами
  • Sorted Set — skip list + hashtable, ZRANGEBYSCORE
  • Stream — consumer groups, XADD/XREADGROUP/XACK
  • HyperLogLog — вероятностный подсчёт уникальных, PFADD/PFCOUNT
  • Bitmap и Bitfield — SETBIT/BITCOUNT, BITFIELD, трекинг DAU
  • Sub — fire-and-forget, SUBSCRIBE/PUBLISH, sharded pub/sub

Атомарность

  • Одна команда — почему отдельная команда всегда атомарна
  • EXEC — транзакции, WATCH/MULTI/EXEC, отсутствие rollback
  • Lua-скрипты — EVAL, KEYS[]/ARGV[], Redis Functions 7.0+

Персистентность

  • RDB — BGSAVE, fork + copy-on-write, компактный snapshot
  • AOF — fsync-политики, rewrite, гибрид RDB + AOF

Управление памятью

Распределение и отказоустойчивость

Практические паттерны

Как всё связано

Redis — система компромиссов, но с другими приоритетами, чем у реляционных СУБД.

Speed vs Durability: Данные в RAM — операции за микросекунды. Цена — при падении без персистентности данные теряются. RDB и AOF смягчают проблему, но не дают ACID-гарантий.

Simplicity vs Functionality: Однопоточная модель исключает гонки и deadlock’и. Цена — медленная команда блокирует весь сервер, нет JOIN’ов и сложных запросов.

Memory vs Capacity: Всё в RAM — быстрый доступ. Цена — объём данных ограничен оперативной памятью, нужны политики вытеснения.

Atomicity vs Flexibility: Одна команда атомарна бесплатно. Для составных операций — EXEC (без условий) или Lua-скрипты (с условиями, но блокируют event loop).

См. также

Sources