Логотип YeaHub

База вопросов

Собеседования

Тренажёр

База ресурсов

Обучение

Навыки

Задачи

Войти

Выбери, каким будет IT завтра — вместе c нами!

YeaHub — это полностью открытый проект, призванный объединить и улучшить IT-сферу. Наш исходный код доступен для просмотра на GitHub. Дизайн проекта также открыт для ознакомления в Figma.

© 2026 YeaHub

AI info

Карта сайта

Документы

Медиа

Назад
Вопрос про Redis : cache, redis

Как организовать кэширование, чтобы сократить количество обращений к базе данных?

Этот вопрос проверяет понимание принципов кэширования: какие кэши бывают, как выбрать ключи, TTL и стратегию обновления, чтобы снизить нагрузку на базу данных и не сломать корректность данных.

Короткий ответ

Кэширование обычно организуют по схеме cache-aside: сначала проверяют кэш, и только при промахе идут в базу данных, сохраняя результат в кэш. Часто используют внешние in-memory хранилища вроде Redis, а также локальный кэш в процессе приложения для самых горячих данных.
Ключи кэша должны однозначно соответствовать запросу (например, user:{id}), а для большинства записей нужно задавать TTL, чтобы данные не устаревали.
Инвалидация кэша делается при изменении данных (удаление/обновление ключа) или через короткий TTL. Важно помнить, что кэш — это ускоритель чтения, и при проектировании нужно балансировать между свежестью данных и производительностью.

Длинный ответ

Кэширование позволяет существенно снизить количество обращений к базе, но требует продуманной схемы ключей, TTL и инвалидации.

1. Где можно кэшировать

Основные варианты:

  1. Локальный кэш в процессе приложения

    • словари, functools.lru_cache, in-memory структуры;

    • очень быстрый доступ, но кэш не разделяется между инстансами.

  2. Внешний кэш (обычно Redis / Memcached)

    • кэш общий для всех инстансов;

    • поддерживает TTL, эвикцию, разные типы структур.

  3. Кэш на уровне БД / прокси

    • например, PgBouncer с prepared statements, query cache в некоторых системах;

    • меньше контроля, но иногда можно получить “бесплатное” ускорение.

Чаще всего в микросервисах используют схему: локальный кэш для супер-горячих данных + Redis как общий кэш.

2. Основные паттерны кэширования

Определение:
Cache-aside (lazy loading) — паттерн, при котором приложение сначала пробует получить данные из кэша, и только при промахе обращается к БД, затем кладёт результат в кэш.

  • Алгоритм:

    1. get(key) из кэша.

    2. Если есть — вернуть.

    3. Если нет — запросить из БД, сохранить в кэш с TTL, вернуть.

Пример (Python + Redis, упрощённо):

import json
import redis

r = redis.Redis(host="localhost", port=6379, db=0)

def get_user(user_id):
    key = f"user:{user_id}"
    cached = r.get(key)
    if cached:
        return json.loads(cached)

    user = load_user_from_db(user_id)  # запрос к БД
    if user:
        r.setex(key, 60, json.dumps(user))  # TTL = 60 секунд
    return user

Другие паттерны (кратко):

  • write-through — при записи в БД сразу пишем в кэш.

  • write-back — пишем в кэш, а в БД синхронизируем асинхронно (сложно, используется реже).

  • read-through — логика чтения из БД спрятана внутри кэша (библиотека/прослойка).

3. Выбор ключей и TTL

Что важно при проектировании:

  • Ключ должен:

    • однозначно соответствовать запросу (user:123, product:42, orders:user:123:page:1);

    • быть достаточно коротким и понятным для отладки.

  • TTL:

    • для редко меняющихся справочников (страны, тарифы) можно задавать большой TTL;

    • для часто меняющихся данных — короткий TTL или явная инвалидация при обновлении.

Пример выбора:

  • профиль пользователя: user:{id}, TTL 1–5 минут;

  • конфигурация: config:{name}, TTL 1 час или без TTL, но с ручной инвалидацией.

4. Инвалидация и обновление кэша

Это самая сложная часть кэширования.

Подходы:

  1. Инвалидация при записи:

    • после успешного UPDATE/INSERT/DELETE в БД:

      • удалить ключ (DEL key),

      • либо обновить значение в кэше.

  2. TTL:

    • позволяет “самообновляться” кэшу со временем;

    • уменьшает риск сильно устаревших данных, но не даёт строгой согласованности.

Для критичных данных часто комбинируют:

  • краткий TTL (например, 30–60 секунд),

  • плюс явная инвалидация при изменении, если это возможно.

5. Типичные ошибки и как их избегать

  • Слишком большой TTL → пользователи видят старые данные.

  • Кэширование "тяжёлых" запросов без продуманной инвалидации → неочевидные баги.

  • Отсутствие лимитов по памяти → Redis или локальный кэш разрастается до упора.

  • Нет метрик кэша:

    • не видим hit rate,

    • не понимаем, помогает кэш или только усложняет архитектуру.

Рекомендуется:

  • мониторить:

    • cache_hits,

    • cache_misses,

    • размер кэша,

    • время ответа Redis.

  • постепенно добавлять кэш на самые “дорогие” запросы.

Краткий вывод

Хорошее кэширование обычно строится на паттерне cache-aside с внешним кэшем (Redis) и продуманными:

  • ключами,

  • TTL,

  • стратегией инвалидации,

  • метриками.

Кэш имеет смысл применять для частых и тяжёлых запросов к БД, где допустима небольшая задержка обновления данных.

  • Аватар

    Python Guru

    Sergey Filichkin

    Guru – это эксперты YeaHub, которые помогают развивать комьюнити.

Уровень

  • Рейтинг:

    5

  • Сложность:

    5

Навыки

  • Redis

    Redis

Ключевые слова

#cache

#redis

Подпишись на Python Developer в телеграм

  • Аватар

    Python Guru

    Sergey Filichkin

    Guru – это эксперты YeaHub, которые помогают развивать комьюнити.