Кейс: рейт-лимит рассчитан на весь трафик, а держал втрое больше
Лимит реализовали как 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 — что спрашивают на самом деле
В этом посте были ссылки, но мы их удалили по правилам Сетки