Пейджер

🌍 Привет мир! 👋🏻

🌍 Привет мир! 👋🏻

Сегодня снова поговорим о чем-то общем, последнее время все чаще встречаюсь с понятием Rate limit при взаимодействии с внешними сервисами или при написании собственных с предоставлением API, тема важна потому что она про стабильность и производительность, Token Bucket Algorithm 🎊!

😮‍💨 Мотивация

Представим ситуацию, вы написали вери вери популярный сервис. Люди, скрипты и боты объединились чтобы заваливать вас запросами. Сначала вы радостно потираете ручки и считаете прибыль 💵, но уже через пару минут сервер падает 💥, ваши действия?

сказать что фронт виноват 😄
Чтобы такого не случалось, нужно использовать rate limiting — ограничивать количество запросов. Как реализовать лимит у себя, решений много, но в данном посте мы поговорим про Token Bucket 👇🏻.

Что за ведро с токенами

Пока на пальцах:

🧩 Представим ведро, в которое с постоянной скоростью (например, 1 токен в секунду) падают «токены».
🧩 Каждый запрос, который поступает на ваш сервис или на какой-то определенный endpoint, должен взять один токен из этого ведра.
🧩 Если токены в ведре закончились, новые запросы временно блокируются (падают в систему ретрай или реджектятся), пока токены снова не накопятся.

У ведра есть два основных параметра:

➡️ Capacity (ёмкость ведра) — сколько токенов максимально может быть в ведре.
➡️ Refill Rate (скорость пополнения) — сколько токенов добавляется в ведро в единицу времени ( это может быть 1s, а может быть и 5 min).

⚙️ Пример (тыкайте)

Представим, что вы делаете приложение для отправки сообщений. И вы хотите, чтобы пользователи были ограничены следующими параметрами исходя из ваших возможностей:

🚨 могли отправить не больше 5 сообщений подряд быстро;
🚨 но при этом в среднем не больше 10 сообщений за минуту (чтобы не спамили).

Получается настройка:

- Capacity = 5 токенов
- Refill rate = 10 токенов / 60 секунд ≈ 0.166 токенов в секунду

class TokenBucket {
  tokens;
  capacity;
  refillRate;
  lastRefill;

  constructor(capacity, refillRate) {
    this.capacity = capacity;
    this.refillRate = refillRate; // Скорость пополнения токенов
    this.tokens = capacity; // Начинаем с полного ведра
    this.lastRefill = Date.now(); // last update
  }

  refillTokens() {
    const now = Date.now();
    const secondsPassed = (now - this.lastRefill) / 1000; // Прошло секунд
    const tokensToAdd = secondsPassed * this.refillRate; // Токенов нужно добавить

    this.tokens = Math.min(this.tokens + tokensToAdd, this.capacity); // Добавляем токены, не превышая capacity
    this.lastRefill = now;
  }

  consume() {
    this.refillTokens(); // Пополняем ведро токенами c учетом last update

    if (this.tokens >= 1) {
      this.tokens -= 1; // Забираем токен
      return true;
    }
    return false; // Токенов нет
  }
}

// Тест
const bucket = new TokenBucket(5, 10 / 60); // 5 токенов максимум, ~0.166 токена в секунду

setInterval(() => {
  if (bucket.consume()) {
    console.log("✅ Успешно!");
  } else {
    console.log("⛔️ Много запросов, жди!");
  }
}, 500);


🎮 Пояснение:

✔️ Запросы идут каждые 0.5 секунды.
✔️ Ведро начинает с 5 токенами, поэтому первые 5 запросов сразу проходят.
✔️ Но токены пополняются медленно (1 токен примерно каждые 6 секунд), поэтому после первых 5 быстрых запросов следующие будут отклоняться, пока снова не накопится хотя бы один токен.

Схема не выглядит сильно сложно, а работает как белорусские часы “Луч” 🔥.
P.S. Луч свяжитесь со мной

💡 Есть и другие решения, и каждое подходит для конкретного отдельного случая, я просто подсвечу:

➡️ Redis позволяет делать глобальные лимиты, можно даже и для нескольких серверов.
➡️ Nginx — быстрый вариант на уровне прокси-сервера, гибкость ограничена.
➡️ API Gateway (Kong...)

Плюсы Token Bucket:

- 🎯 Прямо в коде, без внешних зависимостей.
- 🎯 Гибкие настройки (отдельно можно регулировать burst и среднюю скорость).
- 🎯 Данный алгоритм можно тыкать везде, где есть необходимость что-то останавливать, и необязательно это должно быть API

💬 Если вам понравилась статья, не забудьте поставить лайк и хорошего вам дня! 👍

#ALGORITHMS
Медиа 1
Хотите больше таких постов?
Подпишитесь на канал и читайте продолжение в Telegram.
Подписаться на @ivanchikovitclub Открыть пост в Telegram