> Что такое негативный кэш и почему он вреден (Go)
Уровень: junior · Роль: backend · Категория: Технические вопросы
Компании: VK
Стек: Go
> Пример ответа
Короткий ответ
Негативный кэш - это хранение информации об отсутствии ресурса (например, 404 или ошибки DNS) на некоторое время. Он полезен для снижения нагрузки на сервер, но вреден, когда данные появляются быстро: клиенты продолжают получать устаревший "отрицательный" ответ, хотя ресурс уже доступен. В Go это часто проявляется при кэшировании ошибок от внешних API или БД - закэшированная ошибка блокирует восстановление сервиса.
Подробное объяснение
Негативный кэш работает по принципу: "если запрос завершился неудачей, запомни это на N секунд". Это уменьшает количество повторных запросов к недоступному ресурсу, экономя ресурсы и предотвращая каскадные сбои.
Вред возникает из-за трёх факторов:
- Устаревание данных: если ресурс восстановился через секунду, а TTL негативного кэша - 5 минут, клиенты всё это время получают ложный отрицательный ответ.
- Маскировка проблем: негативный кэш скрывает реальное состояние системы - мониторинг видит стабильные ошибки, хотя причина уже устранена.
- Накопление ошибок: при частичных сбоях (например, один из нескольких реплик БД) негативный кэш может "запомнить" ошибку от одной реплики и игнорировать здоровые.
В Go типичный сценарий - кэширование ошибок от http.Client или database/sql. Если вы сохраняете ошибку в sync.Map или Redis с TTL, вы рискуете тем же.
На практике
Правильный подход - использовать негативный кэш только для стабильных отрицательных ответов (например, 404 для неизменяемых ресурсов) и с коротким TTL. Для временных ошибок (5xx, network timeout) лучше применять retry с экспоненциальной задержкой, а не кэширование.
В Go стоит различать:
- Ошибки бизнес-логики (404, 409) - можно кэшировать с умеренным TTL.
- Инфраструктурные ошибки (connection refused, timeout) - кэшировать нельзя, либо TTL ≤ 1 секунды.
Также важно инвалидировать негативный кэш принудительно: например, при успешном фоновом health-check или при получении сигнала от источника данных.
Пример кода
GOpackage mainimport ("sync""time")type NegativeCache struct {mu sync.Mutexitems map[string]cacheItem}type cacheItem struct {expiresAt time.Time}func (c *NegativeCache) IsNegative(key string) bool {c.mu.Lock()defer c.mu.Unlock()item, ok := c.items[key]if !ok {return false}if time.Now().After(item.expiresAt) {delete(c.items, key)return false}return true}func (c *NegativeCache) SetNegative(key string, ttl time.Duration) {c.mu.Lock()defer c.mu.Unlock()c.items[key] = cacheItem{expiresAt: time.Now().Add(ttl)}}func fetchWithCache(key string, fetch func() (interface{}, error)) (interface{}, error) {// Проверяем негативный кэшif negativeCache.IsNegative(key) {return nil, errors.New("cached negative")}data, err := fetch()if err != nil {// Кэшируем только временные ошибки, TTL короткийnegativeCache.SetNegative(key, 500*time.Millisecond)return nil, err}return data, nil}
Как отвечать на собеседовании
Начните с определения, затем сразу переходите к trade-off: "негативный кэш снижает нагрузку, но создаёт риск устаревших отрицательных ответов". Приведите пример из практики: "в Go при работе с внешним API я бы кэшировал 404, но не 500, и с TTL не больше секунды". Упомяните инвалидацию и мониторинг - это покажет системное мышление. Если спросят про конкретные структуры - скажите про sync.Map или Redis, но подчеркните, что главное - политика TTL и типы ошибок.
Что проверяет интервьюер
- Понимание компромиссов кэширования: скорость vs актуальность.
- Умение различать типы ошибок (временные vs постоянные).
- Знание Go-специфики: конкурентный доступ,
sync.Map,contextдля отмены. - Способность предложить решение с учётом восстановления сервиса.
Типичные ошибки
- Кэшировать все ошибки без разбора - включая 5xx и network timeout.
- Использовать слишком большой TTL (минуты) для негативных ответов.
- Не предусматривать принудительную инвалидацию при восстановлении источника.
- Путать негативный кэш с обычным кэшем данных - у них разные стратегии очистки.
- В Go забывать про гонки данных при работе с map - нужен
sync.Mutexилиsync.Map.
> Похожие задачи по backend
Что такое MITM (man-in-the-middle) атака и как с ней бороться
Стоит ли кэшировать пустые результаты запросов к базе данных
Является ли одиночный update транзакцией
Что такое селективность данных в базах данных
> ГОТОВЫ К СЛЕДУЮЩЕМУ СОБЕСЕДОВАНИЮ?
Запустите тренировочную сессию с ИИ и получите детальную обратную связь, чтобы увереннее проходить реальные интервью