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
Управление памятью
- Внутренние кодировки — redisObject (16 байт), listpack, пороги переключения
- Eviction — maxmemory, 8 политик, приближённые LRU/LFU
- Проектирование ключей — именование ключей, KEYS и SCAN, UNLINK
Распределение и отказоустойчивость
- Репликация и шардинг — общие понятия (failover, кворум, shard key)
- Распределение Redis — что решают репликация, Sentinel и Cluster
- Репликация — master-replica, replication backlog, WAIT
- Sentinel — автоматический failover, кворум
- Cluster — 16 384 слота, hash tags, MOVED/ASK
Практические паттерны
- Кеширование — cache-aside, stampede, early expiration (см. также архитектура кэширования)
- Rate limiting — fixed window, sliding window, token bucket
- Распределённые блокировки — SET NX EX, Lua unlock, Redlock, fencing tokens
- Очереди — LIST-очередь, reliable queue, delayed queue (Sorted Set), Streams
Как всё связано
Redis — система компромиссов, но с другими приоритетами, чем у реляционных СУБД.
Speed vs Durability: Данные в RAM — операции за микросекунды. Цена — при падении без персистентности данные теряются. RDB и AOF смягчают проблему, но не дают ACID-гарантий.
Simplicity vs Functionality: Однопоточная модель исключает гонки и deadlock’и. Цена — медленная команда блокирует весь сервер, нет JOIN’ов и сложных запросов.
Memory vs Capacity: Всё в RAM — быстрый доступ. Цена — объём данных ограничен оперативной памятью, нужны политики вытеснения.
Atomicity vs Flexibility: Одна команда атомарна бесплатно. Для составных операций — EXEC (без условий) или Lua-скрипты (с условиями, но блокируют event loop).
См. также
- Redis в Rails-приложении — клиенты, connection_pool, паттерны использования из Ruby/Rails
Sources
- Redis Documentation. https://redis.io/docs/
- «Redis in Action» — Josiah Carlson, Manning, 2013
- Redis source code. https://github.com/redis/redis