Кейс: рейт-лимит рассчитан на весь трафик, а держал втрое больше

Лимит реализовали как token bucket внутри сервисного бина — Guava RateLimiter, один инстанс на JVM. На одном поде всё сходилось: сервис пропускал ровно столько запросов, сколько заложили в лимите.

После раскатки на три реплики за балансировщиком лимит фактически утроился. Балансировщик распределяет запросы round robin между подами, а у каждого пода своё, никак не связанное с другими, состояние bucket'а. Каждый инстанс честно соблюдал лимит только для своей доли трафика.

// было: состояние живёт в JVM RateLimiter limiter = RateLimiter.create(rps);

Что спросят следом: как сделать rate limiter распределённым без гонки между подами. Ответ — общее хранилище состояния, например Redis с атомарным INCR и EXPIRE на окно, или Lua-скрипт для token bucket, чтобы проверка и списание токена были одной атомарной операцией.

Финал: рейт-лимит без общего состояния ограничивает не трафик системы, а трафик одного пода.

Тренажёр: 600 вопросов, мок с таймером, план повторов

senior·base — что спрашивают на самом деле


В этом посте были ссылки, но мы их удалили по правилам Сетки