Настройка Redis-кэширования для бэкенда мобильного приложения
Мобильный клиент делает запрос за лентой новостей. Бэкенд идёт в PostgreSQL, выполняет JOIN на трёх таблицах, применяет фильтры, сортирует — 200–400 мс. Пользователь обновляет ленту — снова 200–400 мс, хотя данные не изменились. Redis кэширует результат этого запроса, и повторное обращение занимает 1–5 мс. Разница ощущается физически.
Что кэшировать, что нет
Хорошие кандидаты для Redis:
- Результаты тяжёлых агрегирующих запросов (топ пользователей, статистика, каталог)
- Данные, которые запрашиваются часто и меняются редко (конфигурация приложения, настройки, справочники)
- Результаты внешних API-вызовов (геокодирование, курсы валют)
- Сессии и токены аутентификации
Плохие кандидаты:
- Данные конкретного пользователя, которые меняются при каждом его действии
- Транзакционные данные (баланс счёта, статус заказа) — риск показать устаревшее состояние
- Данные с коротким TTL и высокой стоимостью вычисления инвалидации
Архитектура кэширования
Cache-Aside (Lazy Loading)
Самый распространённый паттерн. Приложение сначала проверяет Redis, при промахе — идёт в БД и записывает результат в кэш.
def get_news_feed(user_id: int, page: int):
cache_key = f"feed:{user_id}:page:{page}"
cached = redis.get(cache_key)
if cached:
return json.loads(cached)
data = db.query_feed(user_id, page)
redis.setex(cache_key, 300, json.dumps(data)) # TTL 5 минут
return data
Минус: первый запрос после истечения TTL или cold start всегда медленный. На высоконагруженных API это может привести к thundering herd — сотни запросов одновременно промахиваются в кэш и идут в БД. Защита: mutex lock (через SET NX) или probabilistic early expiration.
Write-Through
При записи данных — сразу обновляем и БД, и кэш. Кэш всегда актуален. Дороже на запись, проще на чтение. Подходит для профилей пользователей, настроек.
Read-Through
Кэш сам знает, как загрузить данные при промахе. Реализуется через Redis modules или библиотеки типа RedisOM. Для большинства мобильных бэкендов избыточно.
Стратегия ключей и TTL
Структура ключей: {сервис}:{сущность}:{id}:{вариант}. Например: app:feed:user:42:page:1, app:config:global:v2.
TTL подбирается под частоту изменений:
- Конфигурация приложения: 1–24 часа
- Каталог товаров: 5–30 минут
- Лента новостей: 1–5 минут
- Профиль пользователя: 5–15 минут
Без TTL кэш растёт до упора памяти. Redis при заполнении памяти с политикой allkeys-lru начинает вытеснять ключи — можно потерять важные данные неожиданно. Явный TTL надёжнее.
Инвалидация
Самая сложная часть. Паттерны:
По событию: при обновлении профиля удаляем app:profile:user:42:* через SCAN + DEL. Не используем KEYS * в продакшене — это O(N) блокирующая операция.
Тегированный кэш: каждому ключу добавляем теги в отдельном set (SADD tag:user:42 "app:feed:user:42:page:1"). При инвалидации — берём все ключи тега и удаляем. Библиотеки Cache-Tags реализуют это автоматически.
Версионирование: вместо инвалидации — смена версии в ключе (app:config:global:v3). Старый ключ просто истечёт по TTL.
Настройка Redis в продакшене
Минимальные требования для мобильного бэкенда:
-
maxmemoryявно ограничиваем (например, 512 МБ) -
maxmemory-policy allkeys-lru— вытеснение наименее используемых ключей при достижении лимита - Persistence: для кэша можно отключить (
save "") — при перезапуске кэш пересоберётся - Sentinel или Redis Cluster для отказоустойчивости в продакшене
Мониторинг: redis-cli INFO stats → keyspace_hits vs keyspace_misses. Hit rate ниже 80% — что-то не так со стратегией кэширования. used_memory и evicted_keys — смотрим постоянно.
Сроки: базовая настройка с Cache-Aside для основных эндпоинтов — два-три рабочих дня. Полноценная стратегия с инвалидацией и мониторингом — четыре-семь дней.







