Skip to content

Commit f78dad7

Browse files
committed
refact: interface and docs
1 parent 0086cff commit f78dad7

File tree

6 files changed

+964
-453
lines changed

6 files changed

+964
-453
lines changed

README.md

+113-33
Original file line numberDiff line numberDiff line change
@@ -1,42 +1,91 @@
1-
# lua-resty-limit-req
1+
# Name
22

3-
lua-resty-limit-req - Limit the request processing rate between multiple NGINX instances
3+
lua-resty-redis-ratelimit - Limit the request processing rate between multiple NGINX instances backed by [Redis](https://redis.io/).
4+
5+
# Table of Contents
6+
7+
* [Status](#status)
8+
* [Description](#description)
9+
* [Synopsis](#synopsis)
10+
* [Methods](#methods)
11+
* [new](#new)
12+
* [incoming](#incoming)
13+
* [set_burst](#set_burst)
14+
* [Author](#author)
15+
* [Copyright and License](#copyright-and-license)
16+
* [See Also](#see-also)
417

518
# Status
619

720
Ready for testing. Probably production ready in most cases, though not yet proven in the wild. Please check the issues list and let me know if you have any problems / questions.
821

9-
## Description
22+
# Description
1023

1124
This lua library is a request processing rate limit module for ngx_lua:
1225

1326
http://wiki.nginx.org/HttpLuaModule
1427

1528
It is used to limit the request processing rate per a defined key between multiple NGINX instances. The limitation is done using the "[leaky bucket](http://en.wikipedia.org/wiki/Leaky_bucket)" method.
1629

17-
This module use redis (>= [2.6.0](http://redis.io/commands/eval)) as the backend storage, so you also need the [lua-resty-redis](https://github.com/openresty/lua-resty-redis) library work with it.
30+
![](./leaky_bucket.png)
31+
32+
This module use Redis (>= [2.6.0](http://redis.io/commands/eval)) as the backend storage, so you also need the [lua-resty-redis](https://github.com/openresty/lua-resty-redis) library work with it.
33+
34+
**NOTICE:** If you do not use the `duration` feature and the incoming traffic is **evenly distrbuted**, it is recommended that use the module [resty.limit.req](https://github.com/openresty/lua-resty-limit-traffic/blob/master/lib/resty/limit/req.md) to avoid unnecessary network delays.
1835

1936
## Synopsis
2037

2138
````lua
22-
lua_package_path "/path/to/lua-resty-limit-req/lib/?.lua;;";
39+
lua_package_path "/path/to/lua-resty-redis-ratelimit/lib/?.lua;;";
2340

2441
server {
2542

2643
listen 9090;
2744

2845
location /t {
29-
access_by_lua '
30-
local req = require "resty.limit.req"
46+
access_by_lua_block {
47+
local ratelimit = require "resty.redis.ratelimit"
48+
49+
local lim, err = ratelimit.new("one", "2r/s", 0, 2)
50+
if not lim then
51+
ngx.log(ngx.ERR,
52+
"failed to instantiate a resty.redis.ratelimit object: ", err)
53+
return ngx.exit(500)
54+
end
55+
56+
-- NOTICE: the following call must be per-request.
57+
58+
-- local redis = require "resty.redis"
59+
-- local red = redis:new()
60+
61+
-- red:set_timeout(1000)
62+
63+
-- local ok, err = red:connect("127.0.0.1", 6379)
64+
-- if not ok then
65+
-- ngx.log(ngx.ERR, "failed to connect redis: ", err)
66+
-- return ngx.exit(500)
67+
-- end
68+
69+
local red = { host = "127.0.0.1", port = 6379, timeout = 1 }
3170

32-
local ok = req.limit{ key = ngx.var.remote_addr, zone = "one",
33-
rate = "2r/s", interval = 2, log_level = ngx.NOTICE,
34-
rds = { host = "127.0.0.1", port = 6379 }}
71+
local key = ngx.var.binary_remote_addr
72+
local delay, err = lim:incoming(key, red)
73+
if not delay then
74+
if err == "rejected" then
75+
return ngx.exit(503)
76+
end
77+
ngx.log(ngx.ERR, "failed to limit req: ", err)
78+
return ngx.exit(500)
79+
end
80+
81+
if delay >= 0.001 then
82+
-- the 2nd return value holds the number of excess requests
83+
-- per second for the specified key.
84+
local excess = err
3585

36-
if not ok then
37-
return ngx.exit(503)
86+
ngx.sleep(delay)
3887
end
39-
';
88+
'}
4089

4190
echo Logged in;
4291
}
@@ -46,51 +95,72 @@ server {
4695

4796
# Methods
4897

49-
## limit
98+
[Back to TOC](#table-of-contents)
99+
100+
## new
101+
102+
**syntax:** `obj, err = class.new(zone, rate, burst, duration)`
103+
104+
Instantiates an object of this class. The class value is returned by the call require `resty.redis.ratelimit`.
50105

51-
`syntax: ok = req.limit(cfg)`
106+
This method takes the following arguments:
52107

53-
Available limit configurations are listed as follows:
108+
* `zone`: Sets the namespace, in particular, we use `<zone>:<key>` string as a unique state identifier inside Redis.
109+
* `rate`: The rate is specified in requests per second (r/s). If a rate of less than one request per second is desired, it is specified in request per minute (r/m). For example, half-request per second is 30r/m.
110+
* `burst`: Defines how many requests can make in excess of the rate specified by the zone, default 0.
111+
* `duration`: The time delay (in seconds) before back to normal state, during this period, the request is always `rejected`, default 0.
54112

55-
* `key`
113+
On failure, this method returns nil and a string describing the error.
56114

57-
The key is any non-empty value of the specified variable.
115+
[Back to TOC](#table-of-contents)
58116

59-
* `zone`
117+
## incoming
60118

61-
Sets the namespace, in particular, we use `<zone>:<key>` string as a unique state identifier inside redis.
119+
**syntax:** `delay, err = obj:incoming(key, redis)`
62120

63-
* `rate`
121+
Fires a new request incoming event and calculates the delay needed (if any) for the current request upon the specified key or whether the user should reject it immediately.
64122

65-
The rate is specified in requests per second (r/s). If a rate of less than one request per second is desired, it is specified in request per minute (r/m). For example, half-request per second is 30r/m.
123+
This method accepts the following arguments:
66124

67-
* `interval`
125+
* `key`: The key is any non-empty value of the specified variable.
126+
* `redis`: Sets the Redis configuration, `host`, `port`, `timeout` and so on (see below); Instead of the specific Redis configuration, you can also sets the connected Redis `object` directly.
68127

69-
The time delay (in s) before back to normal state, default 0.
128+
```
129+
- redis.host: Default 127.0.0.1.
130+
- redis.port: Default 80.
131+
- redis.timeout: Default 1s.
132+
- redis.pass: Request for authentication in a password-protected Redis server.
133+
- redis.dbid: Select the Redis logical database.
134+
```
70135

71-
* `log_level`
136+
The return values depend on the following cases:
72137

73-
Sets the desired logging level for cases when the server refuses to process requests due to rate exceeding, default `ngx.NOTICE`.
138+
1. If the request does not exceed the `rate` value specified in the [new](#new) method, then this method returns `0` as the delay and the (zero) number of excessive requests per second at the current time.
139+
2. If the request exceeds the `rate` limit specified in the [new](#new) method but not the `rate` + `burst` value, then this method returns a proper delay (in seconds) for the current request so that it still conform to the `rate` threshold as if it came a bit later rather than now. The 2nd return value indicating the number of excessive reqeusts per second at this point (including the current request).
140+
3. If the request exceeds the `rate` + `burst` limit, then this method returns `nil` and the error string `"rejected"`.
141+
4. If an error occurred, then this method returns `nil` and a string describing the error. Such as `"failed to create redis - connection refused"`.
74142

75-
* `rds`
143+
This method never sleeps itself. It simply returns a delay if necessary and requires the caller to later invoke the [ngx.sleep](https://github.com/openresty/lua-nginx-module#ngxsleep) method to sleep.
76144

77-
Sets the redis `host` and `port`, default `127.0.0.1` and 6379.
145+
[Back to TOC](#table-of-contents)
78146

79-
- rds.pass: auth redis.
80-
- rds.dbid: select database.
147+
## set_burst
81148

82-
* `conn`
149+
**syntax:** `obj:set_burst(burst)`
83150

84-
Instead of the specific redis configuration (aka. `rds`), sets the connected redis object directly.
151+
Overwrites the `burst` threshold as specified in the [new](#new) method.
85152

153+
[Back to TOC](#table-of-contents)
86154

87155
# Author
88156

89157
Monkey Zhang <timebug.info@gmail.com>, UPYUN Inc.
90158

91159
Inspired from http://nginx.org/en/docs/http/ngx_http_limit_req_module.html.
92160

93-
# Licence
161+
[Back to TOC](#table-of-contents)
162+
163+
# Copyright and License
94164

95165
This module is licensed under the 2-clause BSD license.
96166

@@ -105,3 +175,13 @@ Redistribution and use in source and binary forms, with or without modification,
105175
* Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
106176

107177
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
178+
179+
[Back to TOC](#table-of-contents)
180+
181+
# See Also
182+
183+
* Rate Limiting with NGINX: https://www.nginx.com/blog/rate-limiting-nginx/
184+
* the ngx_lua module: https://github.com/openresty/lua-nginx-module
185+
* OpenResty: https://openresty.org/
186+
187+
[Back to TOC](#table-of-contents)

leaky_bucket.png

29.6 KB
Loading

lib/resty/limit/req.lua

-185
This file was deleted.

0 commit comments

Comments
 (0)