Как определить, когда кэш нужно обновлять в зависимости от типа данных?
Что проверяют
Умеете ли вы выбирать стратегию инвалидации по свойствам данных: как часто они меняются, чем грозит устаревшее значение и кто знает о моменте изменения. Следом обычно спрашивают, как защититься от одновременного пересчёта горячего ключа после истечения TTL.
Как отвечать
Отталкивайтесь от двух вопросов: сколько устаревания допустимо и есть ли событие изменения. Дальше раскладка:
- справочники и конфигурация: меняются редко, устаревание некритично. Длинный TTL в часах плюс сброс при деплое, внутри процесса хватает
functools.lru_cacheилиcachetools.TTLCache; - профили, заказы, настройки пользователя: меняются через ваш же код, значит, момент изменения известен. Cache-aside с удалением ключа после коммита: в Django через
transaction.on_commit(), в FastAPI явным вызовом в сервисном слое; - быстро меняющиеся цены, остатки, курсы: короткий TTL в секундах или вовсе без кэша на критичном пути. Каталог может показывать кэш, а оформление заказа читает из базы;
- данные из чужого API: события изменения нет, поэтому TTL плюс HTTP-механизмы
Cache-ControlиETag, условный запрос сIf-None-Matchэкономит трафик; - тяжёлые агрегаты: stale-while-revalidate, старое значение отдаётся сразу, а пересчёт идёт в фоне через Celery.
В Redis TTL задаётся SET key value EX 60, а при нехватке памяти вытеснение идёт по maxmemory-policy, например allkeys-lru. От stampede защищают блокировка на пересчёт через SET NX, случайный разброс TTL и досрочный пересчёт до истечения.
Где спотыкаются
Ставят один TTL на всё, «пусть будет пять минут». Для справочника это лишняя нагрузка, для складских остатков это пять минут продаж товара, которого уже нет.
Сбрасывают кэш до коммита или внутри транзакции, например в сигнале post_save. Параллельный запрос успевает прочитать из базы старые данные и положить их обратно в кэш, и устаревшее значение живёт до конца TTL.
Кэшируют через lru_cache в приложении, которое крутится в нескольких воркерах gunicorn или uvicorn. У каждого процесса свой кэш, сброс в одном не виден остальным, и пользователь получает разные ответы в зависимости от того, какой воркер его обслужил.