При розробці мобільного додатку з мільйонною аудиторією вузьким місцем став API ендпоінт стрічки новин: запит до PostgreSQL займав 300–500 мс, а при пікових навантаженнях сервер БД захлинався через 10 000 запитів за секунду. Ми впровадили Redis-кешування за патерном Cache-Aside, і час відповіді впав до 2–5 мс, а навантаження на базу знизилося на 70%. Така оптимізація значно скорочує витрати на серверну інфраструктуру — особливо для high-load проектів. Наші інженери мають 7+ років досвіду роботи з Redis у продакшені, впровадили кешування для понад 20 проектів з аудиторією від 1 млн користувачів. За оцінками, впровадження Redis-кешування зменшує щомісячні витрати на хмарні ресурси на $1 500–$3 000.
Які проблеми вирішуємо?
Найчастіша проблема — thundering herd: при закінченні TTL сотні паралельних запитів одночасно йдуть у БД. Другий типовий сценарій — низький hit rate (менше 80%), коли кеш майже не використовується через неправильний вибір даних або TTL. Третя проблема — неконтрольоване зростання пам'яті: без maxmemory Redis може зайняти весь RAM і впасти.
Ми вирішуємо їх за допомогою:
-
Захисту від thundering herd: розподілене блокування через
SET NXабо probabilistic early expiration. - Правильного вибору TTL: підбираємо під частоту змін даних (таблиця нижче).
-
Обмеження пам'яті:
maxmemory 512mb, політикаallkeys-lru.
Як ми це робимо: кейс зі стрічкою новин
Для додатку з 5 мільйонами користувачів ми налаштували Cache-Aside з версіонуванням ключів. Ключ формується як feed:{user_id}:{page}:{version}, де версія змінюється при зміні даних (наприклад, при новому пості). Це дозволило уникнути масової інвалідації. Для захисту від thundering herd використовували блокування:
import redis import json r = redis.Redis() def get_news_feed(user_id: int, page: int, version: int): cache_key = f"feed:{user_id}:{page}:{version}" cached = r.get(cache_key) if cached: return json.loads(cached) # Спроба отримати блокування lock_key = f"lock:{cache_key}" if r.setnx(lock_key, 1): r.expire(lock_key, 5) # 5 секунд на генерацію data = db.query_feed(user_id, page) r.setex(cache_key, 300, json.dumps(data)) r.delete(lock_key) return data else: # Чекаємо і читаємо з кешу повторно import time time.sleep(0.1) return get_news_feed(user_id, page, version) Після впровадження hit rate піднявся з 60% до 95%, кількість evicted_keys впала до нуля. Оптимізація API за допомогою кешування дозволила досягти таких показників.
Чому інвалідація кешу критична?
При прямому оновленні даних у БД кеш залишається застарілим до закінчення TTL. Це призводить до того, що користувачі бачать неактуальну інформацію. Ми використовуємо подієву інвалідацію: при записі в БД надсилається повідомлення (через Kafka або Redis Pub/Sub), яке видаляє відповідні ключі. Для масової інвалідації застосовуємо SCAN з курсором — це безпечно для продакшену на відміну від KEYS *. Більш просунутий підхід — тегований кеш: кожному об'єкту присвоюється тег, який зберігається в SET. При зміні об'єкта видаляємо всі ключі за тегом. Це дає атомарність і контрольовану інвалідацію кешу Redis.
Детальніше про thundering herd
Патерн probabilistic early expiration — ще один метод: за деякий час до закінчення TTL (наприклад, за 10% від TTL) з ймовірністю 10% ми регенеруємо кеш. Це знижує ймовірність одночасного промаху. Redis documentation рекомендує комбінувати блокування та раннє закінчення для максимальної надійності.
Порівняння патернів кешування
| Патерн | Швидкість читання | Консистентність | Складність реалізації |
|---|---|---|---|
| Cache-Aside | Висока | Низька (можливий застарілий запис) | Низька |
| Write-Through | Середня | Висока (завжди актуальні дані) | Середня |
| Read-Through | Висока | Середня | Висока (вимагає Redis modules) |
Як правильно вибрати TTL для кешу
TTL підбирається під частоту змін, і стратегія TTL залежить від типу даних:
| Тип даних | Рекомендований TTL |
|---|---|
| Конфігурація додатку | 1–24 години |
| Каталог товарів | 5–30 хвилин |
| Стрічка новин | 1–5 хвилин |
| Профіль користувача | 5–15 хвилин |
Без TTL кеш зростає до упору пам'яті. Redis при заповненні пам'яті з політикою allkeys-lru починає витісняти ключі — можна втратити важливі дані несподівано. Явний TTL надійніший.
Чому не варто використовувати KEYS у продакшені?
Команда KEYS * блокує Redis на час виконання (O(N)), що неприйнятно при високих навантаженнях. Натомість використовуйте SCAN з курсором та DEL кожного знайденого ключа. Або теги: кожному ключу приписуємо тег у множині SADD tag:user:42 "feed:42:page:1". При інвалідації — SSCAN тега і видаляємо записи. Кеш даних стає гнучкішим.
Що входить у роботу
- Аудит поточної архітектури кешування.
- Проектування схеми ключів, TTL та захисту від thundering herd.
- Реалізація обраного патерну (Cache-Aside / Write-Through).
- Налаштування моніторингу Redis: аналізуйте показники hit rate, пам'ять, evictions.
- Документація та навчання команди.
- Підтримка після впровадження.
Строки: базове налаштування з Cache-Aside для основних ендпоінтів — два-три робочі дні. Повноцінна стратегія з інвалідацією та моніторингом — чотири-сім днів. Для оптимізації кешування мобільного бекенду ми використовуємо перевірені підходи.
Готові прискорити ваш мобільний додаток? Замовте налаштування Redis кешування під ключ — наші фахівці оцінять ваш проект за один день і запропонують оптимальну стратегію. Гарантуємо SLA 99.9%. Отримайте консультацію з впровадження — просто напишіть нам.







