Redis — хранилище данных в памяти
Redis — открытая in-memory база данных типа key-value, которая работает со скоростью порядка 100 000 запросов в секунду. Используется для кэширования, очередей, сессий и многих других задач.
1. Что такое Redis
Redis (Remote Dictionary Server) — это ключ-значение хранилище, данные в котором хранятся преимущественно в оперативной памяти. Благодаря этому чтение и запись выполняются за микросекунды, что делает Redis одним из самых быстрых хранилищ данных.
Сравнение с реляционной БД
| Характеристика | Redis | PostgreSQL / MySQL |
|---|---|---|
| Скорость чтения | ~0.1 мс | ~1–10 мс |
| Хранение | Оперативная память + дамп на диск | Диск |
| Структура | Key-value (без таблиц) | Таблицы с SQL |
| Транзакции ACID | Частичная поддержка | Полная |
| Объём данных | До нескольких ГБ (в памяти) | Терабайты |
Типичные сценарии использования
- Кэш — ускорение доступа к результатам тяжёлых запросов.
- Сессии — хранение сессий веб-пользователей.
- Очереди — reliable queues через LIST и STREAMS.
- Счётчики — подсчёт лайков, просмотров, rate limiting.
- Лидерборды — сортированные множества (ZSET).
2. Установка и запуск
Windows
Официального установщика нет. Используйте форк Memurai или скачайте бинарники с GitHub: github.com/tporadowski/redis.
redis-server --service-install
redis-server --service-startLinux (Debian / Ubuntu)
sudo apt update
sudo apt install redis-server
sudo systemctl enable redis-servermacOS
brew install redis
brew services start redisПроверка работоспособности
Запустите клиент и отправьте пинг:
redis-cli
127.0.0.1:6379> PING
PONG6379 по умолчанию. Убедитесь, что он не заблокирован файрволом.3. Структура данных STRING
STRING — самая простая структура Redis. Значение — произвольная строка до 512 МБ.
SET user:1:name "Иван"
GET user:1:name
SET session:abc "active" EX 60
INCR page:views:home
INCRBY user:1:balance 500
DECR product:stock:42| Команда | Описание |
|---|---|
| SET key value | Записать значение |
| GET key | Получить значение |
| SETEX key seconds value | Записать с TTL |
| INCR key | Увеличить на 1 |
| DECR key | Уменьшить на 1 |
| APPEND key value | Дописать в конец строки |
4. LIST, SET, HASH, ZSET
LIST — двусторонняя очередь
LPUSH queue:tasks "task1" "task2" "task3"
RPUSH queue:tasks "task4"
LPOP queue:tasks
RPOP queue:tasks
LRANGE queue:tasks 0 -1
LLEN queue:tasksSET — неупорядоченное множество
SADD tags:post:1 "python" "redis" "tutorial"
SMEMBERS tags:post:1
SISMEMBER tags:post:1 "redis"
SCARD tags:post:1
SREM tags:post:1 "tutorial"HASH — ассоциативный массив полей
HSET user:1 name "Иван" age "30" email "ivan@mail.ru"
HGET user:1 name
HGETALL user:1
HINCRBY user:1 age 1
HDEL user:1 emailZSET — отсортированное множество
ZADD leaderboard 1500 "player1" 2300 "player2" 1800 "player3"
ZRANGE leaderboard 0 -1 WITHSCORES
ZRANGEBYSCORE leaderboard 1600 2000
ZSCORE leaderboard "player2"
ZREM leaderboard "player1"5. TTL и кэширование
TTL (Time To Live) определяет, сколько секунд значение будет доступно. После истечения ключ удаляется автоматически.
SET cache:homepage "html content" EX 60
TTL cache:homepage
EXPIRE cache:homepage 120
PERSIST cache:homepageПаттерн cache-aside
- Приложение запрашивает ключ.
- Если значение есть в Redis — возвращаем его (кэш-попадание).
- Если нет — читаем из БД, записываем в Redis с TTL и возвращаем.
- При обновлении данных в БД — удаляем ключ из Redis (инвалидация).
6. Redis как кэш для веб-приложений
В реальных проектах Redis берёт на себя роль промежуточного кэша между приложением и основной базой данных. Это позволяет снизить нагрузку на БД в десятки раз для горячих данных.
Кэширование результатов запроса
def get_user_profile(user_id):
cache_key = f"user:{user_id}:profile"
cached = redis_client.get(cache_key)
if cached:
return json.loads(cached)
profile = db.query("SELECT * FROM users WHERE id=%s", user_id)
redis_client.setex(cache_key, 300, json.dumps(profile))
return profileИнвалидация кэша
def update_user(user_id, data):
db.execute("UPDATE users SET ... WHERE id=%s", user_id)
redis_client.delete(f"user:{user_id}:profile")7. Redis из Python
Установка клиентской библиотеки:
pip install redisБазовые операции
import redis
import json
r = redis.Redis(host="localhost", port=6379, decode_responses=True)
r.set("greeting", "Привет, Redis!")
print(r.get("greeting"))
r.hset("user:42", mapping={"name": "Аня", "age": "25"})
print(r.hgetall("user:42"))
data = {"items": [1, 2, 3], "total": 3}
r.setex("cart:99", 600, json.dumps(data))
cached = json.loads(r.get("cart:99"))
print(cached)decode_responses=True автоматически декодирует байты в строки UTF-8.8. Redis из Java
Основная библиотека — Jedis. Добавьте зависимость в Maven:
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
<version>5.1.0</version>
</dependency>Пример использования
import redis.clients.jedis.Jedis;
Jedis jedis = new Jedis("localhost", 6379);
jedis.set("java:key", "Hello from Java");
String value = jedis.get("java:key");
System.out.println(value);
jedis.hset("user:7", "name", "Максим");
jedis.hset("user:7", "age", "28");
System.out.println(jedis.hgetAll("user:7"));
jedis.close();9. Persistence: RDB и AOF
Redis хранит данные в RAM, но поддерживает два механизма сохранения на диск:
RDB — снимки (snaphots)
Redis периодически записывает полный дамп памяти в файл dump.rdb.
save 60 1000
save 300 10
save 3600 1Пример: если за 60 секунд было изменено 1000 ключей — создать снимок.
AOF — журнал операций
Каждая записывающая команда логируется в файл appendonly.aof.
appendonly yes
appendfsync everysec| Параметр | RDB | AOF |
|---|---|---|
| Восстановление | Последний снимок | Перезапуск всех команд |
| Размер файла | Компактный | Может быть большим |
| Производительность записи | Нагрузка в момент снимка | Постоянная |
| Потеря данных | До последнего снимка | До последней fsync |
10. Redis в Docker
Быстрый запуск Redis одной командой:
docker run -d --name my-redis -p 6379:6379 redis:7Подключение к контейнеру
docker exec -it my-redis redis-cli
127.0.0.1:6379> PING
PONGdocker-compose.yml для приложения
version: "3.9"
services:
app:
build: .
ports:
- "8000:8000"
depends_on:
- redis
redis:
image: redis:7-alpine
ports:
- "6379:6379"
volumes:
- redis-data:/data
volumes:
redis-data:redis:7-alpine — образ весит всего ~30 МБ.11. Pub/Sub и репликация
Pub/Sub — система подписок
Redis позволяет создавать каналы для обмена сообщениями в реальном времени.
SUBSCRIBE notifications
PUBLISH notifications "Новый заказ #1234"В приложении подписка обрабатывается асинхронно через listener. Pub/Sub удобен для уведомлений, чатов и real-time обновлений.
Репликация Master-Slave
Redis поддерживает асинхронную репликацию: master передаёт записи на один или несколько slave-серверов.
# На slave-сервере:
REPLICAOF 192.168.1.10 6379
# Проверка роли:
INFO replication- Master обрабатывает все записи (запись).
- Slave получает данные асинхронно (чтение).
- При падении master можно назначить нового master через
REPLICAOF NO ONE.
12. Redis Streams — надёжные очереди событий
Streams — лог-структура, появившаяся в Redis 5.0. В отличие от Pub/Sub, сообщения хранятся в памяти и могут быть прочитаны повторно: потребитель не теряет события, даже если временно отключился или упал.
XADD orders "*" product "42" qty "2"
XLEN orders
XRANGE orders - +
XREAD COUNT 10 STREAMS orders 0-0Каждое сообщение получает монотонный ID вида 1679481234567-0. Группы потребителей распределяют нагрузку между воркерами: команда XREADGROUP выдаёт событие одному из участников, а обработка подтверждается через XACK. Неподтверждённые события остаются в списке pending и читаются заново после рестарта.
- гарантия доставки «хотя бы один раз» с хранением pending;
- срез событий за период через
XRANGE; - основа для сценариев event sourcing.
13. Redis Cluster — горизонтальное масштабирование
Когда данных больше не помещается в память одной машины, на помощь приходит Redis Cluster: данные автоматически делятся по 16384 слотам между узлами, а клиент обращается к любому из них.
redis-cli --cluster create \
192.168.1.10:7000 192.168.1.11:7000 \
192.168.1.12:7000 --cluster-replicas 1
redis-cli -c -p 7000
CLUSTER INFO
CLUSTER SLOTS- мастер-узлы хранят данные, реплики обеспечивают отказоустойчивость;
- ключи с общим префиксом складываются в один слот через теги
{user:42}:cart; - команды, затрагивающие разные слоты, требуют ручной агрегации на клиенте.
14. Производительность и мониторинг
Redis очень быстр, но деградирует при неправильном использовании. Контроль состояния начинается с встроенных команд:
INFO memory
INFO commandstats
SLOWLOG GET 5
redis-cli --stat
redis-cli --bigkeys| Метрика | На что смотреть |
|---|---|
| used_memory_rss | реальное потребление RAM процессом |
| hit_rate / miss_rate | доля эффективных обращений к кэшу |
| evicted_keys | вытеснение ключей при нехватке памяти |
| slowlog | команды, работающие дольше порога (по умолчанию 10 мс) |
Ключи-монстры размером в десятки мегабайт и команды KEYS * в проде запрещены: для перебора используйте SCAN. Для production-наблюдения данные из INFO собирают в Prometheus/Redis Exporter и выводят в Grafana.
maxmemory-policy: allkeys-lru — для кэша, noeviction — для очередей и важных данных.15. Redis Modules: RediSearch, RedisJSON и RedisBloom
Redis с версии 4.0 умеет расширяться модулями. Модуль — это библиотека на C, которая добавляет новые типы данных и команды. Крупные провайдеры (Redis Enterprise, Redis Cloud, некоторые облачные сборки) включают модули из коробки, поэтому знание их возможностей пригодится в реальных проектах.
| Модуль | Что добавляет |
|---|---|
| RediSearch | полнотекстовый поиск и вторичные индексы |
| RedisJSON | JSON-документы с вложенными полями |
| RedisBloom | вероятностные структуры: Bloom, Cuckoo, Top-K |
| RedisTimeSeries | метрики и временные ряды с агрегацией |
FT.CREATE idx:product ON HASH PREFIX 1 "product:" SCHEMA name TEXT price NUMERIC
FT.SEARCH idx:product "note*" LIMIT 0 5
JSON.SET user:5 $ '{"name":"Аня","age":25}'
BF.ADD emails "ivan@mail.ru"RedisJSON хорош, когда структура ответа вложенная, а реляционная схема избыточна. RedisBloom экономит память при подсчёте уникальных значений и защищает кэш от пробития. Учитывайте, что каждый модуль занимает память и добавляет нагрузку на CPU, поэтому подключайте только нужные.
16. HyperLogLog и GEO — счётчики и гео-данные
HyperLogLog (HLL) — вероятностная структура для подсчёта уникальных элементов с фиксированной памятью около 12 КБ, независимо от числа значений. Погрешность ~0.81% — для аналитики «уникальные посетители» это приемлемо, а экономия памяти по сравнению с SET выглядит колоссальной.
PFADD visits:2026:09 "user:1" "user:2" "user:1"
PFCOUNT visits:2026:09
PFMERGE visits:month visits:2026:09 visits:2026:08GEO — индекс гео-координат, хранящий широту и долготу в упорядоченном виде. Он нужен для «ближайшие кафе», «магазины в радиусе 5 км» и расчёта дистанций без внешних сервисов.
GEOADD shops 37.617 55.751 "кафе на Арбате"
GEOSEARCH shops FROMLONLAT 37.62 55.75 BYRADIUS 3 km ASC
GEODIST shops "кафе на Арбате" "кафе 2" km17. Распределённые блокировки
Когда несколько серверов пишут в один ресурс (заказ, загрузка файла), блокировки на уровне приложения недостаточно. Redis раздаёт распределённые лок-и атомарной командой SET ... NX EX: ключ создаётся только если его ещё нет, и с TTL.
SET lock:order:42 "worker-7" NX EX 10
# true — блокировка получена, false — занято
if redis.call("get", KEYS[1]) == ARGV[1] then
return redis.call("del", KEYS[1])
else
return 0
endВторой скрипт — корректное снятие блокировки через Lua: удаляем только свою метку (кто взял, тот и снимает), иначе после истечения TTL один процесс удалит блокировку другого.
- значение ключа — уникальный идентификатор владельца (UUID или id воркера);
- TTL — максимальное время операции, дольше блокировка истекает сама;
- для критических систем рассматривайте Redlock — принятие решения большинством узлов.
SETNX/EXPIRE двумя командами — между ними процесс может упасть. Команда SET key val NX EX атомарна.18. Пробитие, сбой и лавина кэша
Кэш, настроенный как в разделе 6, ломается тремя классическими способами. Пробитие (penetration) — атака несуществующими ключами: каждый запрос проходит сквозь кэш к БД. Сбой (breakdown) — горячий ключ истёк, и десятки запросов одновременно идут в БД. Лавина (avalanche) — истекло много ключей разом, и БД захлёбывается.
| Угроза | Решение |
|---|---|
| пробитие | кэшировать отрицательный результат (null) или фильтр Блума |
| сбой ключа | «лок за обновление» или single-flight |
| лавина | джиттер TTL + рандомная экспирация |
# джиттер: не TTL=300, а TTL=300±random(60)
cache_key = f"user:{uid}:profile"
ttl = 300 + random.randint(-60, 60)
redis.setex(cache_key, ttl, data)- весь кэш с одним TTL — сигнал к лавине; размазывайте экспирацию;
- для негативного кэша берите короткий TTL, чтобы БД «узнала» о новых данных;
- следите за hit_rate и evicted_keys из раздела 14.
19. Транзакции MULTI/EXEC и Lua-скрипты
Несколько команд можно выполнить как единый блок: MULTI ставит их в очередь, а EXEC выполняет все сразу. Пока идёт транзакция, другие клиенты не вклиниваются между командами — блок исполняется атомарно.
MULTI
INCR counter:visits
LPUSH log:visits "2026-09-19"
EXECВажное отличие от реляционных БД: Redis не делает откат (rollback). Если команда упадёт во время выполнения, остальные всё равно применятся. Поэтому перед операциями проверяйте типы значений, а ошибки обрабатывайте на клиенте.
Для атомарной логики с условиями используйте Lua: скрипт передаётся в EVAL и выполняется целиком, без прерывания другими запросами. Пример — списание со счёта только при достаточном остатке:
EVAL "local b = tonumber(redis.call('GET', KEYS[1]))
if b < tonumber(ARGV[1]) then return 0 end
redis.call('DECRBY', KEYS[1], ARGV[1])
return b - ARGV[1]" 1 "account:42" 150| Подход | Когда брать |
|---|---|
| MULTI/EXEC | пакетное выполнение независимых команд |
| Lua-скрипт | условия и зависимости между ключами, атомарный обмен |
| WATCH | оптимистичная блокировка по версии ключа |
SCRIPT LOAD и вызывайте по SHA: трафик между клиентом и сервером уменьшается, а логика не дублируется по языкам.20. Keyspace notifications: события Redis
Redis умеет публиковать события о ключах: создание, изменение, удаление и — самое полезное — истечение TTL. Это открывает путь к «отложенным действиям без очередей»: сброс кэша, холодный старт данных, напоминания.
# в redis.conf или через CONFIG SET
notify-keyspace-events ExСобытия уходят в каналы Pub/Sub двух видов: __keyspace@0__:<ключ> (операция в сообщении) и __keyevent@0__:<операция> (имя ключа в сообщении). Подпишемся на истечение:
SUBSCRIBE __keyevent@0__:expired
# при истечении ключа прилетит: expired user:42:temp| Канал | Что в сообщении |
|---|---|
| __keyspace@0__:user:1 | операция: set, del, expired |
| __keyevent@0__:expired | имя истёкшего ключа |
21. Rate limiting: окна и вёдра
Ограничение частоты запросов — одна из самых частых задач Redis. Простейшая схема — фиксированное окно: инкремент счётчика и TTL на границу окна.
# до 100 запросов на ключ в минуту
val = INCR rate:user:42:minute
if val == 1: EXPIRE rate:user:42:minute 60
if val > 100: отклонить запросФиксированное окно пропускает двойную нагрузку на стыке окон. Точнее — скользящее окно на ZSET: храним метки времени запросов, срезаем старые и считаем свежие.
ZREMRANGEBYSCORE rate:user:42 0 (now-60)
ZCARD rate:user:42
ZADD rate:user:42 now now| Схема | Память | Точность |
|---|---|---|
| fixed window | 1 ключ | умеренная (стыки окон) |
| скользящий ZSET | запись на запрос | высокая |
| token bucket (Lua) | 1–2 ключа | высокая, стабильный «пульс» |
X-RateLimit-Remaining и Retry-After — клиенты смогут вести себя вежливо (см. курс REST API).22. Безопасность Redis: ACL и сетевой контур
Redis по умолчанию отдаёт данные без пароля — на локальной машине это удобно, в проде губительно. Защита строится тремя линиями: сеть, аутентификация и права.
# redis.conf
bind 127.0.0.1 10.0.0.5
protected-mode yes
requirepass "длинный-случайный-пароль"С версии 6.0 доступны ACL: отдельные пользователи со своими паролями и наборами команд. Приложению-кэшу не нужны FLUSHALL и чтение чужих ключей.
ACL SETUSER app on >секрет ~cache:* +@read +@write -@admin
ACL SETUSER readonly on >секрет -@all +get- создавайте пользователя ACL для каждого сервиса — доступ легче отзывать;
- опасные команды (
EVAL,CONFIG,KEYS) запрещайте через ACL, а не переименование; - для трафика между дата-центрами поднимайте TLS (встроенный in Redis 6+) или stunnel.
requirepass защищает только пользователя «default». Если сеть не закрыта файрволом, любой подключившийся может шарить по ключам. Правильный порядок: firewall → bind → protected-mode → ACL.Что дальше
Теперь ты знаешь основы Redis. Рекомендуемый следующий шаг — изучение Redis Streams для продвинутых очередей, Redis Cluster для масштабирования, а также интеграция Redis с веб-фреймворками (Django, Spring Boot) для построения высоконагруженных приложений.