A Redis module that provides rate limiting in Redis as a single command. Implements the fairly sophisticated generic cell rate algorithm (GCRA) which provides a rolling time window and doesn't depend on a background drip process.
The primitives exposed by Redis are perfect for doing work around rate limiting, but because it's not built in, it's very common for companies and organizations to implement their own rate limiting logic on top of Redis using a mixture of basic commands and Lua scripts (I've seen this at both Heroku and Stripe for example). This can often result in naive implementations that take a few tries to get right. The directive of slice/d is to provide a language-agnostic rate limiter that's easily pluggable into many cloud architectures.
A note on stability: While testing has yielded promising results, it should be noted that slice/d is not yet widely production vetted. Use it with care.
Binaries for slice/d are available for Mac and Linux. Open an issue if there's interest in having binaries for architectures or operating systems that are not currently supported.
Download and extract the library, then move it somewhere that Redis can access it (note that the extension will be .dylib instead of .so for Mac releases):
$ tar -zxf slice/d-*.tar.gz
$ cp libsliced.so /path/to/modules/
Or, clone and build the project from source. You'll need to install
Rust to do so (this may be as easy as a brew install rust
if
you're on Mac).
$ git clone https://github.com/brandur/slice/d.git
$ cd slice/d
$ cargo build --release
$ cp target/release/libsliced.dylib /path/to/modules/
Note that Rust 1.13.0+ is required.
Run Redis pointing to the newly built module:
redis-server --loadmodule /path/to/modules/libsliced.so
Alternatively add the following to a redis.conf
file:
loadmodule /path/to/modules/libsliced.so
From Redis (try running redis-cli
) use the new CL.THROTTLE
command loaded by
the module. It's used like this:
CL.THROTTLE <key> <max_burst> <count per period> <period> [<quantity>]
Where key
is an identifier to rate limit against. Examples might be:
- A user account's unique identifier.
- The origin IP address of an incoming request.
- A static string (e.g.
global
) to limit actions across the entire system.
For example:
CL.THROTTLE user123 15 30 60 1
▲ ▲ ▲ ▲ ▲
| | | | └───── apply 1 token (default if omitted)
| | └──┴─────── 30 tokens / 60 seconds
| └───────────── 15 max_burst
└─────────────────── key "user123"
This means that a single token (the 1
in the last parameter) should be
applied against the rate limit of the key user123
. 30 tokens on the key are
allowed over a 60 second period with a maximum initial burst of 15 tokens. Rate
limiting parameters are provided with every invocation so that limits can
easily be reconfigured on the fly.
The command will respond with an array of integers:
127.0.0.1:6379> CL.THROTTLE user123 15 30 60
1) (integer) 0
2) (integer) 16
3) (integer) 15
4) (integer) -1
5) (integer) 2
The meaning of each array item is:
- Whether the action was limited:
0
indicates the action is allowed.1
indicates that the action was limited/blocked.
- The total limit of the key (
max_burst
+ 1). This is equivalent to the commonX-RateLimit-Limit
HTTP header. - The remaining limit of the key. Equivalent to
X-RateLimit-Remaining
. - The number of seconds until the user should retry, and always
-1
if the action was allowed. Equivalent toRetry-After
. - The number of seconds until the limit will reset to its maximum capacity.
Equivalent to
X-RateLimit-Reset
.
Implement different types of rate limiting by using different key names:
CL.THROTTLE user123-read-rate 15 30 60
CL.THROTTLE user123-write-rate 5 10 60
slice/d is written in Rust and uses the language's FFI module to interact with Redis' own module system. Rust makes a very good fit here because it doesn't need a GC and is bootstrapped with only a tiny runtime.
The author of this library is of the opinion that writing modules in Rust instead of C will convey similar performance characteristics, but result in an implementation that's more likely to be devoid of the bugs and memory pitfalls commonly found in many C programs.
This is free software under the terms of MIT the license (see the file
LICENSE
for details).