Redis на практике: кэш, сессии, очереди и лимиты запросов
Практика3 минРедакция Innovialabs
Коротко
Redis — хранилище в памяти для быстрых и недолговечных данных: кэш с TTL, сессии, лёгкие очереди, pub/sub, рейтинги и лимиты запросов, а источником истины остаётся основная база.
Для чего хорош Redis
Redis хранит данные в оперативной памяти и отвечает за микро- и миллисекунды. Поэтому он идеален для данных, которые читаются очень часто, живут недолго или должны быстро считаться. Заменой основной базе он не является: большинство данных в Redis считайте такими, которые можно потерять и восстановить.
Примеры ниже — команды redis-cli; клиентские библиотеки для Node.js, Python, Go и PHP дают те же команды.
Cache-aside с TTL
Приложение сначала смотрит в кэш, при промахе читает из базы и сохраняет результат со сроком жизни.
import json
def get_product(product_id):
key = f"product:{product_id}"
cached = redis.get(key)
if cached:
return json.loads(cached)
product = db.fetch_product(product_id)
redis.set(key, json.dumps(product), ex=300) # TTL 5 минут
return product
def update_product(product_id, data):
db.update_product(product_id, data)
redis.delete(f"product:{product_id}") # инвалидация
Правила, которые спасают от багов:
- Всегда задавайте TTL — устаревшие данные исчезнут, даже если инвалидация не сработала.
- При обновлении удаляйте ключ, а не записывайте новое значение из разных мест кода.
- Добавляйте к TTL небольшой случайный разброс, чтобы тысячи ключей не истекали одновременно.
Хранение сессий
Сессии отлично ложатся на Redis: они небольшие, читаются на каждом запросе и должны истекать.
SET session:9f2c... '{"userId":42,"role":"admin"}' EX 86400
GET session:9f2c...
EXPIRE session:9f2c... 86400 # продление при активности
DEL session:9f2c... # выход из аккаунта
У большинства веб-фреймворков есть готовый адаптер сессий для Redis. Несколько серверов приложения получают общие сессии, и проект можно масштабировать горизонтально.
Простые очереди
Список работает как базовая очередь задач: продюсеры добавляют задачи, воркеры ждут их.
LPUSH queue:emails '{"to":"user@example.com","template":"welcome"}'
BRPOP queue:emails 0 # воркер ждёт, пока появится задача
Слабое место: если воркер упал, забрав задачу, она потеряна. Для надёжной обработки используйте Redis Streams с группами потребителей (XADD, XREADGROUP, XACK) или проверенную библиотеку поверх Redis — BullMQ, Sidekiq, Celery.
Pub/sub
Pub/sub рассылает сообщения всем, кто подписан в данный момент.
SUBSCRIBE orders:new
PUBLISH orders:new '{"orderId":1001}'
Сообщения не сохраняются: подписчик, который был офлайн, их пропустит. Pub/sub подходит для живых уведомлений и инвалидации кэша между серверами, Streams — когда важна доставка.
Рейтинги
Sorted set хранит элементы, упорядоченные по баллам.
ZINCRBY leaderboard:weekly 50 user:42
ZREVRANGE leaderboard:weekly 0 9 WITHSCORES # топ-10
ZREVRANK leaderboard:weekly user:42 # место пользователя
Ограничение запросов
Счётчик с фиксированным окном — самый простой лимитер: считаем запросы по ключу за минуту.
import time
def allow(user_id, limit=60):
key = f"rate:{user_id}:{int(time.time() // 60)}"
count = redis.incr(key)
if count == 1:
redis.expire(key, 60)
return count <= limit
Фиксированное окно допускает всплески на границах. Для более ровного лимита используйте скользящее окно на sorted set или token bucket в Lua-скрипте — так проверка и обновление выполняются атомарно.
Политики вытеснения
Когда Redis достигает maxmemory, поведение определяет настройка maxmemory-policy.
| Политика | Поведение | Когда использовать |
|---|---|---|
noeviction | Отклоняет запись при заполнении | Очереди, данные, которые нельзя терять |
allkeys-lru | Удаляет давно не использованные ключи | Чистый кэш |
allkeys-lfu | Удаляет редко используемые ключи | Кэш со стабильными «горячими» ключами |
volatile-lru | Удаляет только ключи с TTL | Смесь кэша и постоянных данных |
volatile-ttl | Удаляет ключи, которые скоро истекут | Смешанная нагрузка со значимыми TTL |
Частый подход — разные экземпляры Redis: для кэша (allkeys-lru) и для очередей или сессий (noeviction с включённой персистентностью).