1VMOD_VSTHROTTLE(3)                                          VMOD_VSTHROTTLE(3)
2
3
4

NAME

6       vmod_vsthrottle - Throttling VMOD
7

SYNOPSIS

9          import vsthrottle [as name] [from "path"]
10
11          BOOL is_denied(STRING key, INT limit, DURATION period, DURATION block)
12
13          VOID return_token(STRING key, INT limit, DURATION period, DURATION block)
14
15          INT remaining(STRING key, INT limit, DURATION period, DURATION block)
16
17          DURATION blocked(STRING key, INT limit, DURATION period, DURATION block)
18

DESCRIPTION

20       A  Varnish  vmod  for rate-limiting traffic on a single Varnish server.
21       Offers a simple interface for throttling traffic on a per-key basis  to
22       a specific request rate.
23
24       Keys  can  be specified from any VCL string, e.g. based on client.ip, a
25       specific cookie value, an API token, etc.
26
27       The request rate is specified as the number of requests permitted  over
28       a period. To keep things simple, this is passed as two separate parame‐
29       ters, 'limit' and 'period'.
30
31       If an optional duration 'block' is specified, then access is denied al‐
32       together  for that period of time after the rate limit is reached. This
33       is a way to entirely turn away a  particularly  troublesome  source  of
34       traffic  for  a while, rather than let them back in as soon as the rate
35       slips back under the threshold.
36
37       This VMOD implements a token bucket algorithm.  State  associated  with
38       the token bucket for each key is stored in-memory using BSD's red-black
39       tree implementation.
40
41       Memory usage is around 100 bytes per key tracked.
42
43       Example:
44
45          vcl 4.0;
46          import vsthrottle;
47
48          backend default { .host = "192.0.2.11"; .port = "8080"; }
49
50          sub vcl_recv {
51              # Varnish will set client.identity for you based on client IP.
52
53              if (vsthrottle.is_denied(client.identity, 15, 10s, 30s)) {
54                  # Client has exceeded 15 reqs per 10s.
55                  # When this happens, block altogether for the next 30s.
56                  return (synth(429, "Too Many Requests"));
57              }
58
59              # There is a quota per API key that must be fulfilled.
60              if (vsthrottle.is_denied("apikey:" + req.http.Key, 30, 60s)) {
61                      return (synth(429, "Too Many Requests"));
62              }
63
64              # Only allow a few POST/PUTs per client.
65              if (req.method == "POST" || req.method == "PUT") {
66                  if (vsthrottle.is_denied("rw" + client.identity, 2, 10s)) {
67                      return (synth(429, "Too Many Requests"));
68                  }
69              }
70          }
71
72   BOOL is_denied(STRING key, INT limit, DURATION period, DURATION block)
73          BOOL is_denied(
74             STRING key,
75             INT limit,
76             DURATION period,
77             DURATION block=0
78          )
79
80       Arguments:
81
82          • key: A unique identifier to define what is being throttled -  more
83            examples below
84
85          • limit: How many requests in the specified period
86
87          • period: The time period
88
89          • block:  a  period  to deny all access after hitting the threshold.
90            Default is 0s
91
92       Description
93              Can be used to rate limit the traffic for a specific  key  to  a
94              maximum  of  'limit' requests per 'period' time. If 'block' is >
95              0s, (0s by default), then always deny for 'key' for that  length
96              of time after hitting the threshold.
97
98              Note:  A  token  bucket is uniquely identified by the 4-tuple of
99              its key, limit, period and block, so using the same key multiple
100              places with different rules will create multiple token buckets.
101
102       Example
103
104                 sub vcl_recv {
105                         if (vsthrottle.is_denied(client.identity, 15, 10s)) {
106                                 # Client has exceeded 15 reqs per 10s
107                                 return (synth(429, "Too Many Requests"));
108                         }
109
110                         # ...
111                 }
112
113   VOID return_token(STRING key, INT limit, DURATION period, DURATION block)
114          VOID return_token(
115             STRING key,
116             INT limit,
117             DURATION period,
118             DURATION block=0
119          )
120
121       Arguments:
122
123              • Same arguments as is_denied()
124
125       Description
126              Increment (by one) the number of tokens in the specified bucket.
127              is_denied() decrements the bucket by one  token  and  return_to‐
128              ken() adds it back.  Using these two, you can effectively make a
129              token bucket act like a limit on concurrent requests instead  of
130              requests / time.
131
132              Note:  This function doesn't enforce anything, it merely credits
133              a token to appropriate bucket.
134
135              Warning: If streaming is enabled (beresp.do_stream = true) as it
136              is  by  default now, vcl_deliver() is called before the response
137              is sent to the client (who may download it slowly). Thus you may
138              credit  the  token  back  too early if you use return_token() in
139              vcl_backend_response().
140
141       Example
142
143                 sub vcl_recv {
144                         if (vsthrottle.is_denied(client.identity, 20, 20s)) {
145                                 # Client has more than 20 concurrent requests
146                                 return (synth(429, "Too Many Requests In Flight"));
147                         }
148
149                         # ...
150                 }
151
152                 sub vcl_deliver {
153                         vsthrottle.return_token(client.identity, 10, 10s);
154                 }
155
156   INT remaining(STRING key, INT limit, DURATION period, DURATION block)
157          INT remaining(
158             STRING key,
159             INT limit,
160             DURATION period,
161             DURATION block=0
162          )
163
164       Arguments:
165
166              • Same arguments as is_denied()
167
168       Description
169          Get the current number of tokens for a given token bucket. This  can
170          be  used to create a response header to inform clients of their cur‐
171          rent quota.
172
173       Example
174
175                 sub vcl_deliver {
176                    set resp.http.X-RateLimit-Remaining = vsthrottle.remaining(client.identity, 15, 10s);
177                 }
178
179   DURATION blocked(STRING key, INT limit, DURATION period, DURATION block)
180          DURATION blocked(
181             STRING key,
182             INT limit,
183             DURATION period,
184             DURATION block
185          )
186
187       Arguments:
188
189              • Same arguments as is_denied()
190
191       Description
192          If the token bucket identified  by  the  four  parameters  has  been
193          blocked  by  use of the 'block' parameter in 'is_denied()', then re‐
194          turn the time remaining in the block. If it is not  blocked,  return
195          0s.  This can be used to inform clients how long they will be locked
196          out.
197
198       Example
199
200                 sub vcl_deliver {
201                    set resp.http.Retry-After
202                            = vsthrottle.blocked(client.identity, 15, 10s, 30s);
203                 }
204
205
206
207
208                                                            VMOD_VSTHROTTLE(3)
Impressum