Вступить в клуб →
сложнаявопросКонкурентность: горутины, каналы, context

Промах кэша вызывает лавину одинаковых запросов в базу

Кэш каталога в сервисе под 20K RPS устроен так:

func (c *Cache) Get(ctx context.Context, key string) (Item, error) {
    c.mu.RLock()
    v, ok := c.m[key]
    c.mu.RUnlock()
    if ok {
        return v, nil
    }

    v, err := c.loadFromDB(ctx, key) // тяжёлый запрос, ~300 мс
    if err != nil {
        return Item{}, err
    }

    c.mu.Lock()
    c.m[key] = v
    c.mu.Unlock()
    return v, nil
}

В момент истечения записи по популярному ключу в базу одновременно летят сотни одинаковых запросов, p99 подскакивает. Какое решение устраняет причину?

  • Заменить `RWMutex` на обычный `Mutex` — блокировка на чтение перестанет пропускать параллельные промахи
  • Выполнять `loadFromDB` под удержанным `RLock` — тогда параллельные читатели дождутся результата
  • Схлопнуть одинаковые промахи в один вызов на ключ (singleflight): первая горутина идёт в БД, остальные ждут её результат
  • Увеличить TTL записей, чтобы промахи по популярным ключам случались реже и всплески в базу возникали не так часто

🔒 Проверка ответа — для участников клуба

  • Проверка ответа
  • Подсказка, если застряли
  • Разбор с объяснением, почему так
  • Прогресс по всем задачам и виртуальные собеседования
Зарегистрироваться →

Регистрация занимает минуту

Другие задачи раздела