• Stars
    star
    1,189
  • Rank 39,340 (Top 0.8 %)
  • Language
    Rust
  • License
    MIT License
  • Created about 8 years ago
  • Updated 5 months ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

A Redis module that provides rate limiting in Redis as a single command.

redis-cell Build Status

Warning: This package is in "best effort" maintenance mode. I try to respond to opened issues and keep it reasonably up-to-date with respect to the underlying Rust toolchain, but am no longer actively developing it.

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 redis-cell is to provide a language-agnostic rate limiter that's easily pluggable into many cloud architectures.

Informal benchmarks show that redis-cell is pretty fast, taking a little under twice as long to run as a basic Redis SET (very roughly 0.1 ms per command as seen from a Redis client).

Install

Binaries for redis-cell 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 redis-cell-*.tar.gz
$ cp libredis_cell.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/redis-cell.git
$ cd redis-cell
$ cargo build --release
$ cp target/release/libredis_cell.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/libredis_cell.so

Alternatively add the following to a redis.conf file:

loadmodule /path/to/modules/libredis_cell.so

Usage

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"

Response

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:

  1. Whether the action was limited:
    • 0 indicates the action is allowed.
    • 1 indicates that the action was limited/blocked.
  2. The total limit of the key (max_burst + 1). This is equivalent to the common X-RateLimit-Limit HTTP header.
  3. The remaining limit of the key. Equivalent to X-RateLimit-Remaining.
  4. The number of seconds until the user should retry, and always -1 if the action was allowed. Equivalent to Retry-After.
  5. The number of seconds until the limit will reset to its maximum capacity. Equivalent to X-RateLimit-Reset.

Multiple Rate Limits

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

On Rust

redis-cell 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.

License

This is free software under the terms of MIT the license (see the file LICENSE for details).

Development

Tests and checks

Run the test suite:

cargo test

# specific test
cargo test it_rates_limits

# with debug output on stdout
cargo test it_rates_limits -- --nocapture

CI has checks for both Rustfmt and Clippy (Rust's linter). These can be installed and run locally using Rustup's component framework:

rustup component add rustfmt
cargo fmt --all

rustup component add clippy
cargo clippy -- -D warnings

Releasing

Releases are performed automatically from a script in CI which activates when a new tag of the format v1.2.3 is released. The script builds binaries for all target systems and uploads them to GitHub's releases page.

To perform a release:

  1. Add a changelog entry in CHANGELOG.md using the existing format.
  2. Bump the version number in Cargo.toml.
  3. Commit these changes with a message like Bump to version 1.2.3.
  4. Tag the release with git tag v1.2.3 (make sure to include a leading v).
  5. ggpush --tags
  6. Edit the new release's title and body in GitHub (a human touch is still expected for the final product). Use the contents for the new version from CHANGELOG.md as the release's body, which allows Markdown content.

More Repositories

1

sorg

A Go-based static site generator that compiles brandur.org.
Go
486
star
2

json_schema

A JSON Schema V4 and Hyperschema V4 parser and validator.
Ruby
230
star
3

heroku-http-api-design

The Heroku HTTP API Design Guide, forked to look more like its original pre-GitBook state with a more easily digestible single-page format.
167
star
4

hutils

A collection of command line utilities for working with logfmt.
Ruby
108
star
5

tmux-extra

Configuration and scripts for sane Tmux default behavior.
Shell
108
star
6

rocket-rides-atomic

Ruby
94
star
7

sinatra-router

A tiny vendorable router that makes it easy to try routes from a number of different modular Sinatra applications.
Ruby
61
star
8

rhttpserve

A tiny HTTP server that can serve files out of any rclone remote.
Go
39
star
9

rocket-rides-unified

Ruby
27
star
10

podcore

Rust
22
star
11

microservices

21
star
12

blackswan

A project designed to provide personal data ownership and display.
JavaScript
21
star
13

heroku-buildpack-mono

ASP.NET buildpack deployed on top of Mono and XSP.
Shell
18
star
14

postgres-practices

18
star
15

rocket-rides-scalable

Ruby
16
star
16

singularity

A demonstration of a very simple static site generator that deploys to S3 through Travis CI.
Go
15
star
17

dorian

A personal identity manager and aggregator written in Rails 3.1.
JavaScript
13
star
18

casseo

A Graphite dashboard for the command line.
Ruby
12
star
19

modulir

Modulir is an experimental mini-framework for static site generation.
Go
11
star
20

connections-test

Go
10
star
21

wanikaniapi

A Go client for WaniKani's API (https://docs.api.wanikani.com/).
Go
10
star
22

qself

Qself is a small tool to sync personal data from APIs down to local TOML files for easier portability and storage.
Go
10
star
23

cmark2jira

Translate good CommonMark into bad JIRA markup.
Rust
9
star
24

brandur

Go
9
star
25

hncheck

A very simple app that checks to see if something under one of your domains has been submitted to HN, and emails you if it has.
Go
9
star
26

simple-schema

9
star
27

que-degradation-test

Ruby
8
star
28

org

A now defunct project that served my personal site.
8
star
29

mutelight-v2

Content for my technical journal at mutelight.org, designed to be used with Hekla.
Ruby
8
star
30

geotools

Updated mirror for the Geotools.Net project.
C#
8
star
31

redis-haskell

Haskell bindings for Redis, a fast persistent key-value store.
Haskell
7
star
32

logfmt

logfmt parser in Rust.
Rust
7
star
33

hekla

Responsive blogging engine for ephemeral platforms.
JavaScript
7
star
34

mastodon-cross-post

A simple project that cross-posts tweets to Mastodon.
Go
6
star
35

passages-signup

A backend for the signup forms of my newsletters "Nanoglyph" and "Passages & Glass".
Go
6
star
36

heroku-agent

A lightweight process that can communicate with the Heroku CLI and hk to provide more expendient fulfillment of API requests and better convenience of use.
Go
6
star
37

simplebox

Package simplebox provides a simple, easy-to-use cryptographic API where all of the hard decisions have been made for you in advance.
Go
6
star
38

neospring

Go
6
star
39

logs

Ruby
5
star
40

perpetual

Go
5
star
41

slides

An extremely simplistic logs-as-data implementation.
Ruby
5
star
42

rack-instruments

Rack middleware providing basic instrumentation.
Ruby
4
star
43

http_accept

Simple library for HTTP Accept header parsing and ordering.
Ruby
4
star
44

composable

Slides for my talk "Post-Rails? Composable Apps with a First-class API".
JavaScript
4
star
45

middleware-rust

Rust
4
star
46

heroku-mono-build

Heroku-based build recipe for Mono and XSP.
Shell
4
star
47

rack-robots

Rack middleware that denies all robots for staging and development environments.
Ruby
4
star
48

obsidian

Web framework in Haskell to power factz.org. Deprecated in favor of the Rails Facts app.
Haskell
3
star
49

the-surf

Article content for the Surf.
Shell
3
star
50

facts-cli

Command line interface based on Thor for the Facts sever project.
Ruby
3
star
51

mutelight-v1

Nanoc source for my blog at mutelight.org. Deprecated in favor of Askja.
Ruby
3
star
52

artifice-excon

A version of Wycat's Artifice for use with Excon.
Ruby
3
star
53

facts-api

Facts API.
Ruby
3
star
54

heroku-buildpack-mono-build

Builds binaries for the herok-buildpack-mono project.
Shell
2
star
55

db-fill

PLpgSQL
2
star
56

heroku-api-blog

JavaScript
2
star
57

nanowrimo10

My current contribution for National Novel Writing Month. See http://nanowrimo.org.
2
star
58

rakenet

Command line build and testing infrastructure for a .NET project.
Ruby
2
star
59

dping

Ruby
2
star
60

cping

Go
2
star
61

mozjpeg-builder

2
star
62

zendtools.vim

Various useful functions for working in PHP with Zend.
Vim Script
2
star
63

surf

Source code for my blog 'the Surf', uses a custom (and included) static generator.
Ruby
2
star
64

sharks

A scraping and data visualization service for Global Shark Attack File records.
Ruby
2
star
65

spring83-keygen

2
star
66

gal

Go
2
star
67

brandur-old

Rails app to power brandur.org. This has been deprecated in favor of Dorian.
Ruby
2
star
68

service-stub-example

Ruby
2
star
69

imagemagick-builder

2
star
70

sequel-instruments

Basic instrumentation for Sequel.
Ruby
2
star
71

facts-nodejs

Facts database for increasing retention of general knowledge, and for winning arguments. Deprecated in favor of the Rails version.
JavaScript
2
star
72

facts

A tool for getting smarter and winning arguments.
Ruby
2
star
73

d2

A cross-version compatible shortcut for invoking a Ruby debugger.
Ruby
2
star
74

omniauth-heroku

Ruby
2
star
75

postgres-table-rename-test

Ruby
2
star
76

askja

Minimalist blogging platform written in Rails as a flexible alternative to static generators.
Ruby
2
star
77

facts-web

Frontend interface that talks to facts-api.
JavaScript
2
star
78

asp-net-sample

Sample ASP.NET MVC application that can run on Heroku.
C#
1
star
79

wgt2

Go
1
star
80

magmv

A program to rename poorly titled magazine PDF files.
Go
1
star
81

deathguild

Creates Spotify playlists for each night of Death Guild.
HTML
1
star
82

cheat-sheets-dev

A set of cheat sheets designed to centralize information to quicken the development process.
1
star
83

heroku-hyper-schema

1
star
84

umbrella-rust

Rust
1
star
85

certrotate

Go
1
star
86

php-mbstring-overload-tests

Simple test suite to demonstrate PHP's mbstring function overloading.
C
1
star
87

the-surf-old

Next generation of the Surf (journal). Deprecated in favor Hekla.
Ruby
1
star
88

schemadoc

Ruby
1
star
89

fireball

Go
1
star
90

qself-brandur

1
star
91

submodule-dud

1
star
92

archlinux-packages

My contributed PKGBUILDs for the Archlinux AUR.
1
star
93

millstone

1
star
94

neospring-bridge

Go
1
star
95

csrf

Go
1
star
96

wkunburn

Go
1
star
97

dummy

Empty repository.
1
star
98

wgt

A WGT-related playground.
Go
1
star
99

transaction-philosophy

HTML
1
star
100

tailwind-experimenting

CSS
1
star