Slide 1

Slide 1 text

Malte Schlüter

Slide 2

Slide 2 text

Malte Schlüter [email protected] @malteschlueter Malte Schlüter

Slide 3

Slide 3 text

Looking for a Job? https://sensiolabs.de/unternehmen/stellenanzeigen/96454 Malte Schlüter

Slide 4

Slide 4 text

Rate Limiter Experimental $ composer require symfony/rate-limiter Malte Schlüter

Slide 5

Slide 5 text

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

Slide 6

Slide 6 text

Default policies → Fixed Window → Sliding Window → Token Bucket Malte Schlüter

Slide 7

Slide 7 text

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

Slide 8

Slide 8 text

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

Slide 9

Slide 9 text

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

Slide 10

Slide 10 text

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

Slide 11

Slide 11 text

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

Slide 12

Slide 12 text

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

Slide 13

Slide 13 text

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

Slide 14

Slide 14 text

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

Slide 15

Slide 15 text

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

Slide 16

Slide 16 text

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

Slide 17

Slide 17 text

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

Slide 18

Slide 18 text

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

Slide 19

Slide 19 text

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

Slide 20

Slide 20 text

Implementation Examples https://github.com/malteschlueter/demo-rate-limiter Malte Schlüter

Slide 21

Slide 21 text

Questions? Malte Schlüter

Slide 22

Slide 22 text

Thank you! https://speakerdeck.com/malteschlueter Malte Schlüter