Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Introducing the new Rate Limiter component

Introducing the new Rate Limiter component

Short presentation about the new Rate Limiter component in Symfony 5.2.

See https://github.com/malteschlueter/demo-rate-limiter for implementation examples.

Malte Schlüter

January 05, 2021
Tweet

More Decks by Malte Schlüter

Other Decks in Programming

Transcript

  1. Why you want to use it? → Limit requests in

    a specific time → Set different request limitations for authenticated users → Limit it like you implement it Malte Schlüter
  2. Fixed Window Set a limit for a given interval of

    time, like → 5.000 requests per hour → 3 login attempts every 15 minutes Malte Schlüter
  3. Fixed Window Example of a problem → 5.000 requests per

    hour are allowed → A user makes 5.000 requests in the last minute of some hour → And 5.000 requests during the first minute of the next hour → Making 10.000 requests in total in 2 minutes → Possibly the server will overloading Malte Schlüter 4.999 4.999 1 req
  4. Sliding Window → Alternative to the Fixed Window algorithm →

    Designed to reduce bursts → The rate limit is calculated based on the current window and the previous window Malte Schlüter
  5. Sliding Window Example → 5.000 requests per hour are allowed

    → A user makes 4.000 requests the previous hour and 0 requests this hour → At the beginning of this hour there are 1.000 remaining requests → 5.000 - 100% * 4.000 = 1.000 Malte Schlüter
  6. Sliding Window Example → 5.000 requests per hour are allowed

    → A user makes 4.000 requests the previous hour and 0 requests this hour → 15 minutes in to the current hour are 25% of the window → Remaining requests are actual 2.000 requests → 5.000 - 75% * 4.000 = 2.000 Malte Schlüter
  7. Sliding Window Example → 5.000 requests per hour are allowed

    → A user makes 4.000 requests the previous hour and 0 requests this hour → 30 minutes in to the current hour are 50% of the window → Remaining requests are actual 3.000 requests → 5.000 - 50% * 4.000 = 3.000 Malte Schlüter
  8. Sliding Window Example → 5.000 requests per hour are allowed

    → A user makes 4.000 requests the previous hour and 500 requests this hour → 30 minutes in to the current hour are 50% of the window → Remaining requests are actual 2.500 requests → 5.000 - 50% * 4.000 - 500 = 2.500 Malte Schlüter
  9. Sliding Window Example → 5.000 requests per hour are allowed

    → A user makes 4.000 requests the previous hour and 500 requests this hour → 15 minutes in to the current hour are 25% of the window → Remaining requests are actual 1.500 requests → 5.000 - 75% * 4.000 - 500 = 1.500 Malte Schlüter
  10. Token Bucket → A bucket is created with an initial

    set of tokens → A new token is added to the bucket with a predefined frequency (e.g. every second) → If the bucket still contains tokens, the event is allowed; otherwise, it’s denied → If the bucket is at full capacity, new tokens are discarded Malte Schlüter
  11. Configuration Example # config/packages/rate_limiter.yaml framework: rate_limiter: anonymous_api: policy: 'sliding_window' limit:

    100 interval: '60 minutes' authenticated_api: policy: 'token_bucket' limit: 5000 rate: { interval: '15 minutes', amount: 500 } Malte Schlüter
  12. How to implement? class AnonymousLimiterController { public function __construct( private

    RateLimiterFactory $anonymousApiLimiter ) {} // ... } # config/packages/rate_limiter.yaml framework: rate_limiter: anonymous_api: policy: 'sliding_window' limit: 100 interval: '60 minutes' authenticated_api: policy: 'token_bucket' limit: 5000 rate: { interval: '15 minutes', amount: 500 } Malte Schlüter
  13. How to implement? class AnonymousLimiterController { public function __construct( private

    RateLimiterFactory $anonymousApiLimiter ) {} #[Route('/anonymous', name: 'app_anonymous_limiter')] public function __invoke(Request $request): Response { $limiter = $this->anonymousApiLimiter->create($request->getClientIp()); if (!$limiter->consume()->isAccepted()) { return new JsonResponse(['status' => 'error'], Response::HTTP_TOO_MANY_REQUESTS); } return new JsonResponse(['status' => 'ok']); } } Malte Schlüter
  14. How to implement? class AnonymousLimiterController { public function __construct( private

    RateLimiterFactory $authenticatedApiLimiter ) {} #[Route('/anonymous', name: 'app_anonymous_limiter')] public function __invoke(Request $request): Response { $limiter = $this->authenticatedApiLimiter->create($request->headers->get('application_key')); $limiter->reserve()->wait(); return new JsonResponse(['status' => 'ok']); } } Malte Schlüter