Skip to content

Commit d6f258b

Browse files
committed
Updated docs
1 parent 668dde3 commit d6f258b

File tree

1 file changed

+66
-67
lines changed

1 file changed

+66
-67
lines changed

rate_limiter.rst

Lines changed: 66 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -7,19 +7,43 @@ Rate Limiter
77
:doc:`experimental feature </contributing/code/experimental>`.
88

99
A "rate limiter" controls how frequently some event (e.g. an HTTP request or a
10-
login attempt) is allowed to happen. It implements a `token bucket algorithm`_,
11-
which roughly works like this:
10+
login attempt) is allowed to happen. Rate limiting is commonly used as a
11+
defensive measure to protect services from excessive use (intended or not) and
12+
maintain their availability.
13+
14+
Symfony uses these rate limiters in built-in features like "login throttling",
15+
which limits how many failed login attempts a user can make in a given period of
16+
time, but you can use them for your own features too.
17+
18+
Rate Limiting Strategies
19+
------------------------
20+
21+
Symfony's rate limiter implements two of the most common strategies to enforce
22+
rate limits: **fixed window** and **token bucket**.
23+
24+
Fixed Window Rate Limiter
25+
~~~~~~~~~~~~~~~~~~~~~~~~~
26+
27+
This is the simplest technique and it's based on setting a limit for a given
28+
interval of time. For example: 5,000 requests per hour or 3 login attempts
29+
every 15 minutes.
30+
31+
Its main drawback is that resource usage is not evenly distributed in time. In
32+
the previous example, a user could make the 5,000 requests in the first minute
33+
(possibly overloading the server) and do nothing for the rest of the hour.
34+
35+
Token Bucket Rate Limiter
36+
~~~~~~~~~~~~~~~~~~~~~~~~~
37+
38+
This technique implements the `token bucket algorithm`_, which defines a
39+
continuously updating budget of resource usage. It roughly works like this:
1240

1341
* A bucket is initially created with zero or more tokens;
1442
* A new token is added to the bucket with a predefined frequency (e.g. every second);
1543
* Allowing an event consumes one or more tokens;
1644
* If the bucket still contains tokens, the event is allowed; otherwise, it's denied;
1745
* If the bucket is at full capacity, new tokens are discarded.
1846

19-
Symfony uses these rate limiters in built-in features like "login throttling",
20-
which limits how many failed login attempts a user can make in a given period of
21-
time, but you can use them for your own features too.
22-
2347
Installation
2448
------------
2549

@@ -33,39 +57,32 @@ install the associated Symfony Component in your application:
3357
Configuration
3458
-------------
3559

36-
Use the following options to configure the behavior of the rate limiter:
60+
The following example creates two different rate limiters for an API service, to
61+
enforce different levels of service (free or paid):
3762

3863
.. code-block:: yaml
3964
4065
# config/packages/rate_limiter.yaml
4166
framework:
4267
rate_limiter:
43-
limiters:
44-
api_requests:
45-
# maximum number of tokens allowed in the bucket
46-
limit: 100
47-
# how many tokens are created and how often
48-
rate:
49-
amount: 100
50-
interval: '1 hour'
51-
52-
This example creates a rate limiter to restrict the number of HTTP requests of
53-
some API to 100 per hour.
54-
55-
There are other options that you can optionally define if needed:
56-
57-
.. code-block:: yaml
58-
59-
# config/packages/rate_limiter.yaml
60-
framework:
61-
rate_limiter:
62-
limiters:
63-
api_requests:
64-
# ...
65-
lock:
66-
storage:
67-
strategy:
68-
interval:
68+
anonymous_api_limiter:
69+
strategy: fixed_window
70+
limit: 100
71+
interval: 60m
72+
authenticated_api_limiter:
73+
strategy: token_bucket
74+
limit: 5000
75+
rate: { interval: 1h, amount: 5000 }
76+
77+
In the ``anonymous_api_limiter``, when you make the first HTTP request, you can
78+
make up to 100 requests in the next 60 minutes. After that time, the counter
79+
resets and you have another 100 requests for the following 60 minutes.
80+
81+
In the ``authenticated_api_limiter``, when you make the first HTTP request you
82+
are allowed to make up to 5,000 HTTP requests in total, and this number grows
83+
at a rate of another 5,000 requests per hour. If you don't make that number of
84+
requests, the unused ones don't accumulate (the ``limit`` option prevents that
85+
number from being higher than 5,000).
6986

7087
Rate Limiting in Action
7188
-----------------------
@@ -84,11 +101,12 @@ the number of requests to the API::
84101

85102
class ApiController extends AbstractController
86103
{
87-
public function index(LimiterInterface $limiter)
104+
// the variable name must be the exact same as the rate limiter name
105+
public function index(LimiterInterface $anonymous_api_limiter)
88106
{
89107
// the argument of consume() is the number of tokens to consume
90108
// and returns FALSE if they cannot be consumed
91-
if (false === $limiter->consume(1)) {
109+
if (false === $anonymous_api_limiter->consume(1)) {
92110
throw new TooManyRequestsHttpException();
93111
}
94112

@@ -113,53 +131,34 @@ token is available. In those cases, use the ``reserve()`` and ``wait()`` methods
113131

114132
class ApiController extends AbstractController
115133
{
116-
public function registerUser(LimiterInterface $limiter)
134+
public function registerUser(LimiterInterface $authenticated_api_limiter)
117135
{
118136
// this blocks the application until the given number of tokens can be consumed
119-
$limiter->reserve(1)->wait();
137+
$authenticated_api_limiter->reserve(1)->wait();
120138

121139
// ...
122140
}
123141

124142
// ...
125143
}
126144

127-
Creating Multiple Rate Limiters
128-
-------------------------------
145+
Rate Limiter Storage and Locking
146+
--------------------------------
129147

130-
You can define any number of rate limiters in the application. For example, you
131-
could set different API request limits for anonymous and authenticated users:
148+
Rate limiters use the default cache and locking mechanisms defined in your
149+
Symfony application. If you prefer to change that, use the ``lock`` and
150+
``storage`` options:
132151

133152
.. code-block:: yaml
134153
135154
# config/packages/rate_limiter.yaml
136155
framework:
137156
rate_limiter:
138-
limiters:
139-
# 1 request per minute for anonymous users
140-
anonymous_api_requests:
141-
limit: 1
142-
rate:
143-
amount: 1
144-
interval: '1 minute'
145-
# 85 requests per minute for authenticated users
146-
authenticated_api_requests:
147-
limit: 85
148-
rate:
149-
amount: 85
150-
interval: '1 minute'
151-
152-
Now you can inject each rate limiter using the same name as in the configuration::
153-
154-
// src/Controller/LuckyController.php
155-
// ...
156-
157-
class ApiController extends AbstractController
158-
{
159-
public function index(LimiterInterface $authenticated_api_requests)
160-
{
161-
// ...
162-
}
163-
}
157+
anonymous_api_limiter:
158+
# ...
159+
# the value is the name of any cache pool defined in your application
160+
storage: 'app.redis_cache'
161+
# the value is the name of any lock defined in your application
162+
lock: 'app.rate_limiter_lock'
164163
165164
.. _`token bucket algorithm`: https://en.wikipedia.org/wiki/Token_bucket

0 commit comments

Comments
 (0)