Token bucket rate limiter на чистом PHP без Redis
Часто вижу реализации rate limiter завязанные на Redis или другие внешние хранилища. Но для однопроцессных скриптов, CLI-утилит или быстрого прототипирования нужен вариант без зависимостей.
Вот рабочая реализация алгоритма token bucket на чистом PHP:
Запустите в sandbox, увидите что первые 10 проходят сразу (burst), потом начинает ограничивать до 5 rps. Меняйте usleep и параметры чтобы понять поведение.
Хорошая реализация. Добавлю вариант для случая когда нужно ограничивать разные ключи независимо, например по IP:
Запустите, видно что два IP ограничиваются независимо.
Важное замечание по Swoole: в корутинном окружении microtime(true) работает корректно, но сам объект TokenBucket нельзя шарить между корутинами как статическое свойство, иначе получите race condition на $this->tokens.
В Hyperf для такого используйте либо coroutine context, либо вынесите состояние в атомарный счетчик через Swoole\Atomic\Long. Вот упрощенный пример с атомарным счетчиком для однотипного ограничения:
Единственный минус который замечаю: отладка. Когда цепочка падает, стектрейс указывает на всю выражение целиком а не на конкретный шаг. Пока не придумал удобного способа это обойти кроме как разбивать на переменные при дебаге.
Для продакшн кода с важной логикой пока предпочитаю явные переменные именно по этой причине. Для трансформации данных типа sanitize/format pipeline очень удобно.
```php blocks are runnable.